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).
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.