【发布时间】:2020-11-27 08:25:06
【问题描述】:
我正在学习结构填充,并读到结构填充背后的原因是,如果结构的成员未对齐,处理器将无法在一个周期内读取/写入它们。通常,由N 字节组成的数据类型的位置应该是N 的倍数的地址。
假设这个结构例如:
struct X
{
char c;
// 3 bytes padding here so that i is aligned.
int i;
};
这里这个struct的大小应该是8个字节,c默认是对齐的,因为它只占1个字节,而i不是。对于i,我们需要在它之前添加 3 个字节的填充,以便它“对齐”并且只能在一个周期内访问。如果我遗漏了什么,请告诉我。
1 - 对齐如何工作?成员与什么结盟?
2 - CPU 访问位于N 倍数地址的N 字节数据类型有什么好处?为什么例如在上面的结构中,如果i位于地址XXX3(以3结尾,换句话说,不是4的倍数),为什么不读取从地址XXX3开始的单词呢?为什么一定是4的倍数?大多数 CPU 访问的地址是否仅为字长的倍数?我相信 CPU 可以从任何字节开始从内存中读取一个单词。我错了吗?
3 - 为什么编译器不对成员重新排序以尽可能多地占用空间?排序重要吗?我不确定是否有人使用实际的偏移量来访问成员。这意味着如果有一个结构X x,通常会像这样访问成员:x.i 而不是*(&x + 4)。在后一种情况下,排序实际上很重要,但在第一种情况下(我相信每个人都使用),排序应该无关紧要。我必须注意,在这个例子中,如果i 出现在c 之前也没关系,最后会有一个 3 字节的填充。我一般问为什么?
4 - 我读到这不再重要了,CPU 现在通常可以访问非对齐成员,花费与对齐成员相同的时间。真的吗?如果是,那为什么?
最后,如果有好的地方可以了解更多,我将不胜感激。
【问题讨论】:
-
对齐是一个平台架构约束。与某些架构上的对齐访问一样,未对齐的数据访问可能代价高昂(性能高达 x16),并且可能阻碍原子读/写(仅与多线程应用程序相关),或者完全不受支持(导致进程故障)。其他架构可以毫无问题地处理它们,其他架构也可以处理它们,但会降低性能(因此编译器会在性能方面出错)。
-
@ssd 如问题 2 所述,如果我在地址
XXX3处有一个 double,那么为什么不从地址XXX3开始读取整个 8 个字节? CPU不能访问内存中的任何位置吗?为什么这个例子中的地址应该是 8 的倍数? -
@StackExchange123 :是的,CPU 可以访问那块内存,您可以通过编写自己的汇编代码来实现这一点。编译器只是优化成块读取。
-
@StackExchange123 :我用谷歌搜索发现某些 CPU(例如 arm)具有编译器指令(
-munaligned-access),您可以关闭此对齐访问的东西. -
阅读此article。
标签: c++ c struct padding memory-alignment