Sta*_*123 5 c c++ struct padding memory-alignment
我正在学习结构填充,并了解到结构填充背后的原因是,如果结构的成员未对齐,处理器将无法仅在一个周期内读取/写入它们。一般来说,由N字节组成的数据类型的位置应该是 的倍数的地址N。
假设这个结构体例如:
struct X
{
char c;
// 3 bytes padding here so that i is aligned.
int i;
};
Run Code Online (Sandbox Code Playgroud)
这里这个结构体的大小应该是8个字节,c默认是对齐的,因为它只占用1个字节,但i事实并非如此。对于i,我们需要在其前面添加 3 个字节的填充,使其“对齐”并且只能在一个周期内访问。告诉我我是否遗漏了什么。
1 - 对齐是如何工作的?成员们的立场是什么?
2 - 对于 CPU 访问N位于 的倍数地址的字节数据类型,什么更好N?例如,在上面的结构体中,如果i位于地址XXX3(以 3 结尾,换句话说,不是 4 的倍数),为什么不读取从地址开始的单词XXX3?为什么一定是4的倍数?大多数 CPU 访问的地址是否仅为字大小的倍数?我相信 CPU 可以从内存中的任意字节开始读取一个字。我错了吗?
3 - 为什么编译器不重新排序成员以便占用尽可能多的空间?顺序重要吗?我不确定是否有人使用实际的偏移量来访问成员。这意味着如果有一个 struct X x,通常会像这样访问成员:x.inot *(&x + 4)。在后一种情况下,顺序实际上很重要,但在第一种情况下(我相信每个人都使用),顺序不重要。我必须注意,在这个例子中,这并不重要,因为如果也i出现在前面c,那么末尾会有 3 个字节的填充。我一般都问为什么?
4 - 我读到这不再重要了,CPU 现在通常可以与对齐成员花费相同的时间来访问不对齐成员。真的吗?如果是的话为什么?
最后,如果有一个可以学习的好地方,我将不胜感激。
他们至少对齐到_Alignof(type)。原则上允许实现进一步对齐,但这通常是不可取的,并且没有主要的实现这样做。
正如 Eljay(强调我的)评论中指出的那样:
\n\n\n对齐是平台架构的约束。在某些架构上,未对齐的数据访问可能与对齐访问一样昂贵(性能昂贵高达 16 倍),并且可能会阻碍原子读/写(仅与多线程应用程序相关),或者完全不受支持(导致进程故障)。其他架构可以毫无问题地处理它们,而其他架构也可以处理它们,但会带来性能损失(因此编译器会在性能方面犯错误)。
\n
编写语言标准是为了考虑到此类平台限制。
\n不允许这样做,至少如果结构地址的获取方式使表示对应用程序可见的话则不允许这样做。语言规范要求成员按顺序排列。这是6.7.2.1 结构和联合说明符, \xc2\xb615:
\n\n\n在结构体对象中,非位域成员和位域所在的单元的地址按照它们声明的顺序递增。指向结构对象的指针经过适当转换后,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然。结构对象内可能有未命名的填充,但不是在其开头。
\n
不,这不是真的。高端 cpu 通常会透明地修补未对齐的访问,以允许某些类型的草率代码以及必然未对齐的操作(例如memcpy或memmove通过具有不同对齐方式的缓冲区),但这并不能改变这些操作往往更多的事实昂贵并且它们不适用于原子操作等某些操作。