0

有各种pragma用于控制结构/类布局的 s,例如pragma pack. 但据我所知,没有pragma理由说“我不关心布局。它是内部的,代码不依赖它。重新排序以获得最佳性能/大小。”。AFAIK,这是典型的案例,它可以在许多情况下提高性能/大小。此外,即使程序员足够小心地根据性能/大小对其重新排序,不同的目标架构也可能具有不同的最佳布局。

编辑:澄清一下,我说的是成员的顺序。填充已经是可控的。

此外,PVS-Studio 也有相关消息。这就是我要说的——为什么编译器不能用pragma?

4

2 回答 2

2

该语言特别指出,类成员在内存中的排序方式与它们在每个访问级别中的顺序相同(如private)。编译指示无法覆盖此行为。

见 9.2/14:

分配具有相同访问控制(第 11 条)的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址。未指定具有不同访问控制的非静态数据成员的分配顺序

请记住,重新排序成员会更改调用子对象构造函数和析构函数的顺序,可能还有其他事情。即使给编译器提供编译指示以在幕后进行此类更改,这似乎也极具风险(如果您的成员依赖于另一个成员的初始化怎么办)。

于 2014-10-16T15:49:24.700 回答
1

语言标准将允许这样的编译指示,但我不知道有任何编译器实现了这样的事情。

在 C 中, 的行为在标准#pragma的第 6.10.6 节中指定(链接是最新草案):


#pragma pp-tokens opt new-line形式的预处理指令,
其中预处理标记STDC不立即跟随pragma在指令中(在任何宏替换之前)导致实现以实现定义的方式运行。该行为可能会导致翻译失败或导致翻译器或生成的程序以不合格的方式运行。任何不被实现识别的编译指示都会被忽略。

所以 a #pragma can实际上违反了语言规则。

在这种情况下,相关规则是结构成员按照它们声明的顺序排列。6.7.2.1 第 15 段:

在结构对象中,非位域成员和位域所在的单元的地址按声明顺序递增。一个指向结构对象的指针,经过适当的转换,指向它的初始成员(或者如果该成员是位域,则指向它所在的单元),反之亦然。结构对象中可能有未命名的填充,但不是在其开头。

坏消息:C 标准要求结构成员按照声明的顺序排列。第一个成员必须在偏移量 0 处。成员之间可能有任意填充,或者在最后一个之后,但它们不能重新排序。

好消息:该语言允许实现定义一个#pragma违反上述规则的布局。

坏消息:据我所知,实际上没有任何实现这样做。即使有,也有其他实现没有,所以任何使用这样的代码#pragma都是不可移植的。(尽管至少如果 的名称#pragma是唯一的,任何不识别它的编译器都需要忽略它,因此您的代码仍然可以编译。)

那是针对 C 的。C++ 规则#pragma与 C 规则非常相似。我有理由确定结构布局的 C++ 规则也类似于 C;继承使事情变得更复杂一些。

于 2014-10-16T18:04:53.953 回答