Search code examples
cstructassignment-operator

C: does the assignment operator deep copy?


For scalar values, the assignment operator seems to copy the right-hand side value to the left. How does that work for composite data types? Eg, if I have a nested struct

struct inner {
    int b;
};

struct outer {
   struct inner a;
};

int main() {
   struct outer s1 = { .a = {.b=1}};   
   struct outer s2 = s1;
}
  • does the assignment recursively deep copy the values?
  • does the same happen when passing the struct to a function?

By experimenting it seems like it does, but can anyone point to the specification of the behavior?


Solution

    • does the assignment recursively deep copy the values?

      Yes, just as if you would have used memcpy. Pointers are copied, but not what they point at. The term "deep copy" often means: also copy what the pointers point at (for example in a C++ copy constructor).

      Except the values of any padding bytes may hold indeterminate values. (Meaning that memcmp on a struct might be unsafe.)

    • does the same happen when passing the struct to a function?

      Yes. See the reference to 6.5.2.2 below.

    • By experimenting it seems like it does, but can anyone point to the specification of the behavior?

      C17 6.5.16:

      An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after the assignment, but is not an lvalue. The type of an assignment expression is the type the left operand would have after lvalue conversion.

      (Lvalue conversion in this case isn't relevant, since both structs must be of 100% identical and compatible types. Simply put: two structs are compatible if they have exactly the same members.)

      C17 6.5.16.1 Simple assignment:

      • the left operand has an atomic, qualified, or unqualified version of a structure or union type compatible with the type of the right;

      C17 6.5.2.2 Function calls, §7:

      If the expression that denotes the called function has a type that does include a prototype, the arguments are implicitly converted, as if by assignment, ...