我理解结构成员之间发生的填充,以确保各个类型的正确对齐。但是,为什么数据结构必须是最大成员对齐的倍数?我不明白最后需要填充。
答案 0 :(得分:7)
好问题。考虑这种假设类型:
struct A {
int n;
bool flag;
};
因此,A
类型的对象应该占用五个字节(四个用于int加一个用于bool),但实际上它需要八个字节。为什么呢?
如果你使用这样的类型,就会看到答案:
const size_t N = 100;
A a[N];
如果每个A
只有五个字节,那么a[0]
会对齐a[1]
,a[2]
,而大多数其他元素则不会。
但为什么对齐甚至重要?有几个原因,都与硬件有关。一个原因是最近/经常使用的内存缓存在CPU芯片上的缓存行中以便快速访问。小于高速缓存行的对齐对象总是适合单行(但请参见下面附带的有趣注释),但未对齐的对象可能跨越两行,浪费缓存。
实际上存在更多基本硬件原因,与字节可寻址数据沿32位或64位数据总线传输的方式有关,与高速缓存线完全不同。不对称会导致总线堵塞额外的提取(由于之前的跨越),但它也会迫使寄存器在进入时移位字节。更糟糕的是,未对准往往会混淆优化逻辑(至少,英特尔的优化手册说虽然我对最后一点没有个人了解,但确实如此。因此,从绩效的角度来看,错位是非常糟糕的。
由于这些原因,浪费填充字节通常是值得的。
更新:以下评论都很有用。我推荐他们。
答案 1 :(得分:1)
根据硬件的不同,可能需要对齐,或者只是帮助加快执行速度。
有一定数量的处理器(我相信ARM),其中未对齐访问会导致硬件异常。简单明了。
即使典型的x86处理器更宽松,但访问未对齐的基本类型仍然存在一些损失,因为处理器必须做更多的工作才能将这些位带入寄存器,然后才能对其进行操作。编译器通常在需要打包时提供特定的属性/编译指示。
答案 2 :(得分:0)
由于虚拟寻址。
“...在页面大小的边界上对齐页面可以让... 硬件通过替换将虚拟地址映射到物理地址 地址中的较高位,而不是复杂的算术。“
顺便说一下,我发现维基百科的页面写得非常好。
答案 3 :(得分:0)
如果CPU的寄存器大小为32位,则它可以使用单个汇编指令获取32位边界的存储器。获取32位的速度较慢,然后从第8位开始获取字节。
顺便说一句:没有填充。你可以要求打包结构。