Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C结构填充是否使此使用不安全?_C_Memory_Struct_Size_Unions - Fatal编程技术网

C结构填充是否使此使用不安全?

C结构填充是否使此使用不安全?,c,memory,struct,size,unions,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; 我听说有些编译器会自动填充结构,通过创建单词对齐的边界来提高性能 据推测,这种协同

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

    typedef struct {
        union {
            struct { float x, y, z; } xyz;
            struct { float r, g, b; } rgb;
            float xyz[3];
        } notAnonymous;
    } Vector3;
我听说有些编译器会自动填充结构,通过创建单词对齐的边界来提高性能

据推测,这种协同作用意味着无法保证结构的大小是其组件字段大小的总和,因此在以下情况下,数组
xyz
会发生数据损坏和/或溢出:

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

正确吗?

的确,编译器可以在您的结构中添加它想要的任何类型的填充。您可以使用
#pragma pack
uuu属性((packed))
来避免大多数编译器上的填充。实际上,这里有三个32位字段,所以可能不会有问题。您可以在结构类型或该类型的变量上使用
sizeof
进行检查,并查看结果

问题是您试图在最后两行中将
Vector3
分配给
float
变量。这是不允许的。你可以侵入你想做的事情:

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

但这看起来很难看,更不用说令人困惑了。最好将
xyz
更改为
Vector3
数组,而不仅仅是
float

参见C缺陷报告074中的问题解答


这不是天生的不安全,编译器/链接器负责所有的偏移量


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

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


话虽如此,至少在我的书中,,这种黑客行为是为了语法醋而对未定义行为的无端调用,是不可接受的。如果有机会访问数组样式的数据,只需始终使用数组形式即可。记住向量组件总是
v[0]
v[1]
v[2]
比记住
v[1]
rgb.g
可能引用内存中的同一个对象要容易得多…

关于
\uu属性((打包))
,请参见约定-不要忘了注意安全!愚蠢的我-是的,我当然需要演员,我已经改变了我的代码,以反映你所说的。令人困惑的本质并不影响我的问题,许多GL代码可能看起来令人困惑,这更多是关于功能而不是美学。我的示例中的32位字段也是一个很好的观点——我应该选择更畸形的代码。将您的评论的准确性和#pragma hint的实际相关性标记为选择答案。非常感谢!由于链接文档的高度技术性,我对这篇文章投了赞成票,但没有选择它作为我的首选答案。