除了'n字节对齐'之外,类型是否有可能具有对齐要求

时间:2013-11-23 19:01:57

标签: c++ memory-alignment

例如,请考虑以下事项:

假设int是4字节对齐的,而long是8字节对齐的。

struct example
{
    int a;
    long b;
    int c;
};

编译器在内存中放置它的明显方法是: AAAAPPPPBBBBBBBCCCCPPPP,整个结构具有8字节对齐。

  • P表示填充字节
  • A指的是
  • 的字节
  • B指的是b
  • 的字节
  • C指的是c
  • 的字节

在这种情况下,sizeof(示例)为24。

但另一种方法是: AAAABBBBBBBBCCCC与整个结构有对齐,使得起始字节mod 8的地址= 4(不确定怎么说这个更简洁)

在这种情况下,不需要填充,因此每个实例可以节省8个字节。

我的问题是,编译器是否允许这样做(按标准)?他们真的这样做了吗?我总是看到对齐仅以字节为单位进行讨论。

3 个答案:

答案 0 :(得分:2)

结构不能具有不比其成员的对齐要求严格的对齐要求。如果结构的成员是8字节对齐的,则结构需要至少8字节对齐。如果结构是8字节对齐的,那么在您的示例中,第二个成员不会是8字节对齐,因为它从8字节对齐的结构的开头偏移了四个字节,因此它不符合要求

可能的替代方法是将padding放在struct的开头,但不允许这样做:

C ++ 03 9.2p17

  

指向POD结构对象的指针(适当地使用reinterpret_cast转换)指向其初始成员(...),反之亦然。 [注意:因此,在POD结构对象中可能存在未命名的填充,但不是在其开头,以实现正确的对齐。]

另一种可能的替代方案是(正如你的建议)让8字节对齐实际意味着((address%8)==4)(而不是(address%8)==0)。如果是这种情况,那么你的8字节对齐long具有相同的要求。不可能同时具有(address%8)==0(address%8)==4对齐的类型,因为没有办法一般地分配满足两者的内存对齐要求。由于long也会有这种特殊的对齐要求,你仍然无法避免填充。

答案 1 :(得分:2)

你忘记了数组。在一般情况下,你如何建议编译器应该确保每个数组元素在数组的情况下“起始字节mod 8 = 4”?

请记住,C语言要求对于T a[N]类型的任何数组对象,以下都适用

sizeof a == sizeof *a * N

这意味着整个数组对象a中存在的任何填充必须来自T类型的单个元素。不允许数组添加自己的填充。

换句话说,编译器不能简单地记住正确对齐各个struct对象。它实际上必须将填充包含在struct对象中,并将该填充计为该结构对象的sizeof的一部分。

你的AAAABBBBBBBBCCCC是一个“好”的,因为当这些对象紧凑地存储在一个数组中时(没有额外的填充),如果数组的第一个元素正确对齐,它们都会正确对齐。但是,如果数组内存由malloc分配,那么您期望如何实现第一个元素的正确对齐? malloc对分配内存的类型一无所知,这意味着它无法根据您的类型的特定对齐要求定制其行为。

答案 2 :(得分:0)

编译器将尝试通过添加填充来对齐每个成员。通常存在最大对齐,这取决于编译器和处理器(例如,通常您没有像256字节对齐那样的对齐)。这个最大对齐甚至不存在于标准中,因此编译器对齐大小为2048的结构并非不可能......

正如DyP在评论中所说,gcc可以将其打包为:

AAAA PPPP BBBB BBBB CCCC PPPP

Live example

请注意,它可以采用其他方式打包(在Ideone上使用double进行试用并与Stacked-Crooked进行比较)。

如果您不想填充,可以使用预处理器指令:

#pragma pack

这与gccMSVC兼容。

有了这个,用于前一个示例的相同版本的gcc将其打包为:

AAAA BBBB BBBB CCCC

Live example