C:赋值运算符是否进行深度复制?

时间:2019-06-11 10:42:10

标签: c struct assignment-operator

对于标量值,赋值运算符似乎将右侧值复制到左侧。这对复合数据类型如何起作用?例如,如果我有嵌套的结构

struct inner {
    int b;
};

struct outer {
   struct inner a;
};

int main() {
   struct outer s1 = { .a = {.b=1}};   
   struct outer s2 = s1;
}
  • 该分配是否递归地深度复制值?
  • 将结构传递给函数时会发生同样的事情吗?

通过尝试似乎可以做到,但是任何人都可以指出行为规范吗?

2 个答案:

答案 0 :(得分:4)

没有“递归”;它复制值的所有(值)位。当然,并不是神奇地遵循指针,赋值运算符不会知道如何复制指向的数据。

你会想到的

a = b;

简写

memcpy(&a, &b, sizeof a);

sizeof当然是令人误解的,因为我们知道双方的类型都是相同的,但我认为__typeof__并没有帮助。

C11规范草案说(在6.5.16.1简单分配中,第2段):

  

在简单赋值(=)中,右操作数的值将转换为   赋值表达式的类型,并替换存储在对象中的值   由左操作数指定。

答案 1 :(得分:2)

  •   

    该分配是否递归地深度复制值?

    是的,就像您将使用memcpy一样。指针被复制,但不指向它们。 “深度复制”一词通常意味着:还复制指针指向的内容(例如在C ++复制构造函数中)。

    除任何填充字节的值外,其他值可能都不确定。 (这意味着结构上的memcmp可能是不安全的。)

  •   

    将结构传递给函数时会发生同样的事情吗?

    是的。请参阅下面对6.5.2.2的引用。

  •   

    通过尝试似乎可以做到,但是任何人都可以指出行为规范吗?

    C17 6.5.16:

      

    赋值运算符将一个值存储在由左操作数指定的对象中。一个   赋值表达式具有赋值后的左操作数的值,但不具有   一个左值。赋值表达式的类型是左操作数应具有的类型   左值转换后。

    (在这种情况下,左值转换无关紧要,因为两个结构必须都是100%相同且兼容的类型。简而言之:如果两个结构具有完全相同的成员,则它们是兼容的。)

    C17 6.5.16.1简单分配:

      
        
    • 左操作数具有结构或联合的原子,合格或不合格版本   类型与权利的类型兼容;
    •   

    C17 6.5.2.2函数调用,第7节:

      

    如果表示被调用函数的表达式的类型确实包含原型,   参数被隐式转换,就像通过赋值一样,...