类型是否可以具有除'n-byte alignment'以外的对齐要求

Is it possible for a type to have alignment requirements other than 'n-byte alignment'

本文关键字:对齐 alignment n-byte 类型 是否      更新时间:2023-10-16

例如,考虑以下内容:

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

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

编译器在内存中布局的明显方式是:AAAAPPPPBBBBBBCCCCPPPP,整个结构具有8字节对齐。

  • P表示填充的字节
  • A指的是
  • B表示B的一个字节
  • C表示C的一个字节

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

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

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

我的问题是,编译器(按照标准)可以这样做吗?他们真的这么做了吗?我经常看到以字节为单位简单地讨论对齐。

结构的对齐要求不能低于其成员的对齐要求。如果结构的一个成员是8字节对齐的,那么该结构至少需要8字节对齐。如果结构是8字节对齐的,那么在您的示例中,第二个成员将不会是8字节排列的,因为它从一个8字节对齐结构的开头偏移了四个字节,所以它不符合要求。

可能的替代方案是在结构的开头放置填充,但这是不允许的:

C++03 9.2p17

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

另一种可能的选择是(正如您所建议的)让8字节对齐实际上意味着((address%8)==4)(与(address%8)==0相反)。如果是这种情况,那么您的8字节对齐的long将具有相同的要求。不可能同时具有(address%8)==0(address%8)==4对齐的类型,因为没有办法通用地分配满足这两种对齐要求的内存。由于long也有这种特殊的对齐要求,您仍然无法避免填充。

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

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

sizeof a == sizeof *a * N

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

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

AAAABBBBBBBBCCCC是一个"不错"的对象,因为当这些对象被紧凑地存储在数组中(没有额外的填充)时,如果数组的第一个元素正确对齐,它们最终都会正确对齐。但是,例如,如果数组内存由malloc分配,您希望如何实现第一个元素的正确对齐。malloc对正在为其分配内存的类型一无所知,这意味着它无法根据您的类型的特定对齐要求调整其行为。

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

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

AAAA PPPP BBBB BBBB CCCC PPPP

活生生的例子。

请注意,它可以用另一种方式包装(在Ideone上用double试试,并与Stacked Crooked进行比较)。

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

#pragma pack

这与gcc和MSVC兼容。

有了这个,上一个例子中使用的gcc的相同版本将其打包为:

AAAA BBBB BBBB CCCC

活生生的例子。