cpointersstructmemcpy

Is assigning a struct variable to itself (via pointer dereferencing) defined behaviour?


If two pointers are pointing to the same struct variable, is it defined behaviour to assign one dereferenced pointer to the other?

struct Struct {
    int member;
};

int main() {
    struct Struct s, *p1, *p2;
    s.member = 1234;
    p1 = p2 = &s;
    *p1 = *p2; // is this allowed?
}

I mainly ask because in this SO post and this SO post a number of answers state that struct assignment is more or less equivalent to memcpy, and some compilers even generate a memcpy call for the assignment statement. However, memcpy is not defined when the memory locations overlap, which begs the question: is it defined for assignment?

This appears to be behaving as expected, but I would like to know if the C standard has anything to say about it. Is it necessary to add a simple check

if (p1 != p2) *p1 = *p2;

or use memmove instead?


FYI, this came up when I was implementing my own slot map (as described here) in C. When removing an element from the container, the element at the end of the array gets copied to the deleted location to keep everything contiguous. In the case where the deleted element is at the end of the array, it will get copied to itself (not super important since that element is considered to be deleted, but got me curious anyway).


Solution

  • The assignment is well defined. A corresponding call to memcpy would not be.

    Here's what the standard says about simple assignment N1570 6.15.6.1 paragraph 3):

    If the value being stored in an object is read from another object that overlaps in any way the storage of the first object, then the overlap shall be exact and the two objects shall have qualified or unqualified versions of a compatible type; otherwise, the behavior is undefined.

    whereas for memcpy (7.24.2.1 paragraph 2):

    If copying takes place between objects that overlap, the behavior is undefined.

    So it's not correct that struct assignment is equivalent to memcpy, though the "more or less" qualification is appropriate. For one thing, as we see here, memcpy between exactly overlapping objects is undefined, while assignment is well defined. For another, memcpy preserves the values of any padding bytes (gaps between members or after the last one), while assignment is not guaranteed to do so. Assignment could be implemented by copying each member rather than by copying the entire structure.

    That being said, an implementation could implement assignment and memcpy in exactly the same way. The fact that some cases have undefined behavior means that an implementation is free to do anything convenient.