C如何处理结构赋值

时间:2012-08-14 14:57:47

标签: c struct variable-assignment

假设我有这样的结构:

typedef struct {
    char *str;
    int len;
} INS;

该结构的数组。

INS *ins[N] = { &item, &item, ... }

当我尝试访问其元素时,不是作为指针,而是作为struct本身,所有字段都被复制到临时本地?

for (int i = 0; i < N; i++) {
    INS in = *ins[i];
    // internaly the above line would be like:
    // in.str = ins[i]->str;
    // in.len = ins[i]->len;
}

因此,当我增加结构字段时,这将是一个更昂贵的赋值操作?

4 个答案:

答案 0 :(得分:2)

正确,in*ins[i]副本

不要介意你的内存消耗,但你的代码很可能不正确:对象in在循环体的末尾死亡,以及你对{{{ 1}}没有持久的效果!

答案 1 :(得分:1)

结构分配的行为类似于memcpy。是的,对于更大的结构来说它更贵。矛盾的是,你的结构越大,衡量增加另一个领域的额外费用就越难。

答案 2 :(得分:1)

是的,struct在C中有value semantics。因此,将结构分配给另一个将导致成员方式的副本。请记住,指针仍将指向相同的对象。

答案 3 :(得分:1)

编译器可能优化结构的副本,而是直接从数组访问成员以提供使用副本的C代码中所需的值,或者可以仅复制单个成员使用。一个好的编译器会做到这一点。

通过指针存储值可能会干扰此优化。例如,假设您的例程还有一个指向int p的指针。当编译器处理您的代码INS in = *ins[i]时,它可以“思考”类似这样的内容:“复制ins[i]代价很高。相反,我会记得in是一个副本,我会在以后使用它们时获取成员。“但是,如果您的代码包含*p = 3,则可能会更改{{1}除非编译器能够推断出ins[i]没有指向p。 (有一种方法可以帮助编译器使用ins[i]关键字进行扣除。)

总结:表面看起来很昂贵的操作可能会被一个好的编译器有效地实现。看起来便宜的操作可能很昂贵(写入restrict打破了一个很大的优化)。通常,您应该编写清楚表达算法的代码并让编译器进行优化。

扩展编译器如何优化它。假设你写:

*p

其中“...”中的代码访问in.str和in.len,但不添加任何其他237个成员添加到INS结构中。然后,编译器可以自由地将此代码转换为:

for (int i = 0; i < N; i++) {
    INS in = *ins[i];
    ...
}

即使你写了一个声明,表面上复制了所有INS结构,编译器只需要复制实际需要的部分。 (实际上,甚至不需要复制这些部分。只需要生成一个程序,该程序可以获得相同的结果就像它直接遵循源代码一样。)