3

我们知道 C 中的某些结构中存在填充。请考虑以下 2:

struct node1 {
      int a;
      int b;
      char c;
};

struct node2 {
      int a;
      char c;
      int b;
};

假设sizeof(int) = alignof(int)= 4 bytes:
sizeof(node1) = sizeof(node2) = 12,由于填充。

两者在性能上有什么区别?(如果有的话,wrt 编译器或系统架构,尤其是 GCC)

4

4 回答 4

4

这些都是不好的例子——在这种情况下它并不重要,因为在任何一种情况下填充量都是相同的。不会有任何性能差异。

编译器将始终努力在 a 的末尾填充尾随填充,struct否则使用结构数组是不可行的,因为第一个成员应始终对齐。如果不是某些 item 的尾随填充struct_array[0],那么第一个成员struct_array[1]最终会错位。


但是,如果我们要这样做,顺序将很重要:

struct node3 {
      int  a;
      char b;
      int  c;
      char d;
};

假设4字节int和4字节对齐,那么b这里占用1+3字节,d另外还有1+3字节。如果两个成员相邻放置,这可能会写得更好char,在这种情况下,填充的总量将只有 2 个字节。

于 2020-09-10T08:36:48.623 回答
1

好的,我可能在这里完全不合时宜,因为这有点超出我的范围。如果是这样,请纠正我。但这就是我的看法:

首先,为什么我们需要填充和对齐?这只是浪费字节,不是吗?好吧,事实证明处理器喜欢它。也就是说,如果您向 CPU 发出一条对 32 位整数进行操作的指令,CPU 将要求该整数驻留在可被 4 整除的内存地址中。对于 64 位整数,它需要驻留在一个可被 8 整除的地址。等等。这样做是为了使 CPU 设计更简单,性能更好。

如果您违反此要求(也称为“未对齐的内存访问”),大多数 CPU 将引发异常。x86 实际上是一个奇怪的东西,因为它仍然会执行操作 - 但它会花费两倍以上的时间,因为它将通过两次而不是一次从内存中获取值,然后执行按位魔法将值从这些单独的访问中粘在一起.

所以这就是编译器向结构添加填充的原因 - 以便所有成员都正确对齐并且 CPU 可以快速(或根本)访问它们。好吧,这是假设结构本身位于正确的内存地址。但是,只要您坚持标准操作来分配内存,它也会解决这个问题。

但是可以明确地告诉编译器您也想要不同的对齐方式。例如,如果你想使用你的结构从一个紧密打包的文件中读取一堆数据,你可以显式地将填充设置为 1。在这种情况下,编译器还必须发出额外的指令来补偿潜在的错位。

TL;DR - 错误的对齐会使一切变慢(或者在某些情况下可能会使您的程序完全崩溃)。

然而,这并没有回答“在哪里更好地放置填充?”的问题。需要填充,是的,但是在哪里?好吧,它直接并没有太大的区别,但是通过仔细重新排列您的成员,您可以减小整个结构的大小。使用更少的内存通常意味着更快的程序。特别是如果您创建这些结构的大型数组,使用更少的内存将意味着更少的内存访问和更有效的 CPU 缓存使用。

但是,在您的示例中,我认为没有任何区别。

PS 为什么你的结构以填充结尾?因为数组。编译器希望确保如果您分配这些结构的数组,它们都将正确对齐。因为数组成员之间没有任何填充。

于 2020-09-10T12:52:32.290 回答
1

如果面试官的意见是基于将来扩展结构时向后兼容的旧论点,我不会感到惊讶。附加字段 ( char, smallint) 可能会受益于尾随填充占用的空间,而不会影响现有字段的内存偏移量。

在大多数情况下,这是一个有争议的问题。该方法本身可能会破坏兼容性,原因有两个:

  1. 在新的对齐边界上开始扩展(就像 发生的那样node2)可能不是内存最佳的,但它可以很好地防止新字段被“旧”结构的填充意外覆盖。
  2. 当兼容性是一个很大的问题时(例如,在持久化或传输数据时),那么序列化/反序列化(即使需要二进制)比依赖于每个架构、每个编译器甚至不同的二进制格式更有意义每个编译器选项。
于 2020-09-10T10:41:53.570 回答
0

两者在性能上有什么区别?

性能差异是“无法确定的”。在大多数情况下,它不会有任何区别。

对于确实有所作为的情况;任何一个版本都可能更快,具体取决于结构的使用方式。例如,如果您有大量这些结构的数组,并且经常“随机”选择数组中的一个结构;那么如果你只访问随机选择的结构ab第一个版本可以更快(因为ab更有可能在同一个缓存行中),如果你只访问ac那么第二个版本可以更快。

于 2020-09-10T11:50:03.150 回答