C struct padding是否会使这种使用不安全?

时间:2012-01-11 22:13:34

标签: c memory struct size unions

假设我有一个结构,无论是联合还是其他:

    typedef struct {
        union {
            struct { float x, y, z; } xyz;
            struct { float r, g, b; } rgb;
            float xyz[3];
        } notAnonymous;
    } Vector3;

我听说有些编译器通过创建字对齐边界来自动填充结构以增强性能。

大概这样的协同作用意味着结构的大小不能保证是其组件字段大小的总和,因此下面的数组xyzs的数据损坏和/或溢出发生了变化: / p>

inline Vector3 v3Make(float x, float y, float z) { Vector3 v = {x,y,z}; return v; }
float xyzs[6];
*(Vector3*)&xyzs[3] = v3Make(4.0f,5.0f,6.0f);
*(Vector3*)&xyzs[0] = v3Make(1.0f,2.0f,3.0f);

正确?

4 个答案:

答案 0 :(得分:3)

编译器可以使用它想要的任何类型的填充来构建我们的结构。您可以使用#pragma pack__attribute__((packed))来避免大多数编译器的填充。实际上,你有三个32位字段,所以它可能不会成为一个问题。您可以在结构类型或该类型的变量上使用sizeof进行检查,看看会发生什么。

的问题在于您尝试在最后两行中为Vector3变量分配float。这是不允许的。你可能会破解你想要做的事情:

*(Vector3 *)&xyzs[3] = v3Make(4.0f, 5.0f, 6.0f);

但那看起来很丑陋,更不用说令人困惑了。将xyzs更改为Vector3而不仅仅是float的数组会更好。

答案 1 :(得分:2)

查看C缺陷报告#074中问题的答案

http://www.open-std.org/jtc1/sc22/wg14/docs/rr/dr_074.html

答案 2 :(得分:0)

它本身并不安全,编译器/链接器会处理所有偏移。

除非 ...您将结构传递给另一个用另一种语言或另一个系统编写的程序,或者在同一系统上使用相同语言编写但具有不同编译器设置的另一个程序。然后可能无法正确计算偏移量。

答案 3 :(得分:0)

根据C标准,这至少是实现定义的(取决于填充问题)和未定义的行为(由于别名规则?),但是在所有真实编译器上它都会按预期工作。类型的对齐永远不会大于它的大小(它总是均匀地划分类型的大小),并且只有病态上不好的编译器会在结构中插入额外的填充,超出了将每个成员填充到其类型的正确对齐所需的填充。

有了这个,在我的书中至少,这种黑客是为了句法醋而无端调用未定义的行为,是不可接受的。如果您有可能想要以数组样式访问数据,只需使用数组表单即可。记住向量组件总是v[0]v[1]v[2]比记住v[1]rgb.g可能引用相同的内容要少得多。记忆中的对象......