3

代码 1:-

struct emp
{
  char a;
  double b;
};
int main()
{
    struct emp e;
    printf("%p    %p", (void*)&e.a, (void*)&e.b);
}

在我的电脑上输出:-

OO28FF00    0028FF08

由于 和 的大小分别chardouble“1”和“8”,因此0028FF00和分别是“1”和“8”0028FF08的倍数。

代码 2:-

struct emp
{
  char a;
  long double b;
};
int main()
{
    struct emp e;
    printf("%p    %p    \n", (void*)&e.a,(void*)&e.b);
}

输出是: -

0028FF00    0028FF04

char因为和的大小分别long double是 '1' 和 '12' 但0028FF04不是 '12' 的倍数。

为什么在这种情况下不应用填充?

4

3 回答 3

3

Along double是一个80 位浮点数,因此您需要 10 个字节。不过,10 确实不是一个很好的大小,因此英特尔 32 位处理器决定使用 12 字节。12 是 4 的倍数,表示 32 位(3 x 32 位)。这被认为是对齐的,因为 32 位处理器只需要 4 字节对齐,因此 12 字节在任何 4 字节边界对齐。显然,编译器知道它在做什么,它总是试图生成尽可能小的结构。

话虽这么说,这是您看到不能使用结构声明并希望将其按原样保存在文件中的地方……至少不能使用默认的 C 类型(您可以使用 int32_t、uint64_t 等来准确获取你想要什么,但浮点数没有等价物......)

正如有人评论的那样,在 64 位架构上,long double 是 16 个字节。浪费了 6 个字节……但它使类型始终对齐 64 位。

于 2014-02-08T07:57:55.397 回答
2

维基百科有一个典型对齐表:

x86 具有灵活的内存访问指令,因此规则由编译器设计者决定。我们只能想象为什么他们认为有最合理的。

我发现@LưuVĩnhPhúc 的评论很有教育意义。尽管long double在您的平台上是 12 字节(GCC?),但它是 4 字节对齐的,原因与 512 字节结构不会 512 字节对齐的原因相同;空间会浪费太多。我猜 GCC 的设计者认为访问double变量应该以尽可能少的延迟完成,代价是一些空间(最多 7 个字节)。

于 2014-02-08T08:05:10.260 回答
0

好吧,据我所知,填充和数据对齐在很大程度上取决于目标架构、编译器优化选项和优化器的整体质量。因此,如果你不特别关心对齐,你会得到一个“准最优”结构,编译器可以自由决定什么对这组特定的优化选项更好(使用 -Os 还是 -O 等等) . 如果你希望有一个特定的对齐,你应该使用编译器特定的选项来调整这些东西。对于 GCC 和 CLang 使用__packed__属性,对于 MSVC 使用#pragma pack. 有关更多信息,请参阅pragma pack(1) 和 __attribute__ ((aligned (1))) 作品

于 2014-02-08T07:48:15.567 回答