C++ 编译器可以重新排序结构中的元素吗

Posted

技术标签:

【中文标题】C++ 编译器可以重新排序结构中的元素吗【英文标题】:Can a C++ compiler re-order elements in a struct 【发布时间】:2010-10-29 07:57:48 【问题描述】:

C++ 编译器(特别是 g++)可以重新排序结构的内部元素吗?

我看到一些奇怪的行为,我的结构包含以下内容:

Struct SomeStruct
   ...
   ...
   long someLong;
   long someLongArray[25];
   unsigned long someUnsignedLong;
   unsigned long someUnsignedLongArray[8];
   unsigned long int someUnsignedLongInt;
   ...
   ...
;

当我将输出写入文件时,someUnsignedLongArraysomeLongArray 的顺序似乎颠倒了(即 someLongArray[] 中的元素出现在 someUnsignedLong 之后,而 someUnsignedLongArray[] 的元素出现在 someLong 之后)。这可能吗??

谢谢


更新: 根据要求,我正在使用以下内容写出结构:

int fd = open(fspec,O_RDWR|O_CREAT|O_TRUNC,0666);
int writeRes =  write(fd,(char *)&someStruct,sizeof(SomeStruct));

为了完整起见,这里是完整的结构:

struct SomeStruct
byte someByte;
byte someByteArray[6];
char someChar;
char someCharArray[5];
char someCharArrayArray[3][5];
short someShort;
signed short someShortArray[2];
unsigned short someUnsignedShort;
unsigned short someUnsignedShortArray[8];
int someInt;
int someIntArray[3];
int someIntArrayArrayArrayArray[4][3][2][6];
int *pSomeInt;
unsigned int someUnsignedInt;
unsigned int someUnsignedIntArray[9];
long someLong;
long someLongArray[25];
unsigned long someUnsignedLong;
unsigned long someUnsignedLongArray[8];
unsigned long int someUnsignedLongInt;
long long someLongLong;
long long someLongLongArray[5];
bool someBool;
bool someBoolArray[3];
unsigned long long someUnsignedLongLong;
unsigned long long someUnsignedLongLongArray[5];
unsigned long long someUnsignedLongLongArrayArray[5][2];
unsigned long long int *pSomeUnsignedLongLongInt;
;

【问题讨论】:

如何将结构写入文件? 你确定你看到的是你认为你看到的吗?即,您是否在每个元素中写入了独特的位模式并可以将它们跟踪到文件中?还有你在结构周围使用什么#pragma pack(如果有的话)? 也许他正在将结构的字节而不是结构的元素写入文件。 你可以替换“...”并编写一个显示问题的主函数吗?结构中的其他内容以及如何将其写入文件会有所不同。您是否将 SomeStruct* 转换为 char* 并写入 sizeof(SomeStruct) 字节或其他内容? 顺便说一句:您可以使用 offsetof 检查字段的顺序,而无需将任何内容写入磁盘。 【参考方案1】:

它通常不能重新排序元素,不。

如果有一个访问说明符将它们分开,则例外:

struct Foo     
  A a;
  B b;
  C c;
private:
  D d;
  E e;
  F f;
;

abc保证按此顺序存储,def保证按顺序存储。但不能保证abc 相对于def 的存储位置。

要记住的另一件事是编译器可以根据需要插入尽可能多的填充,即使它不重新排序任何内容。

这是标准的相关部分:

第 9.2.12 节:

a 的非静态数据成员 (非联合)类声明没有 干预访问说明符是 分配给后来的成员 类中的更高地址 目的。分配顺序 非静态数据成员由 访问说明符未指定 (11.1)"

【讨论】:

只是好奇您是否对此有引用?我不是说你错了,但引用会很有用。 我认为只有 POD 不能在访问说明符块中重新排序。非 POD 完全没有订单要求。但既然你正在为 Doug T 查找它,而且我的副本一直在楼上,我会让你检查一下 ;-) oof,我想我最好再查一下... ;) 9.2.12 说“在没有干预访问说明符的情况下声明的(非联合)类的非静态数据成员被分配,所以后面的成员在类对象中具有更高的地址。由访问说明符分隔的非静态数据成员的分配顺序未指定(11.1)。 @onebyone:有趣的是,它似乎没有说明 POD 与非 POD。如果你确定的话,我会让你看看那个。 ;) 我不确定 - 出于某种原因,我认为关于订单的内容在 POD 部分,但显然不是。【参考方案2】:

不能,请参阅Automated field re-ordering in C structs to avoid padding 和Why doesn't GCC optimize structs? 了解更多信息。

我不知道你所说的“反转”是什么意思,也许你应该添加一些代码和输出。

【讨论】:

当我说反转时,我的意思是 someUnsignedLongArray[] 中的元素直接出现在 someLong 之后。我会澄清这个问题。 这不是因为它不允许,而是因为它很复杂并且会破坏很多东西。 GCC 能够做到这一点,并且对其的研究仍在进行中。见Is there a GCC keyword to allow structure-reordering?

以上是关于C++ 编译器可以重新排序结构中的元素吗的主要内容,如果未能解决你的问题,请参考以下文章

C中的结构内存布局

使用选择算法编译时间递归排序

C 结构中的自动字段重新排序以避免填充

如果我布置结构的字段以便它们不需要任何填充,那么符合标准的 C++ 编译器可以添加额外的东西吗?

C++ 结构可以在不同的编译时间有不同的对齐方式吗?

C++容器详解