“64位机器”这个术语是含糊的。计算机处理器和系统有几个特性,它们在同一台机器上可能具有不同的大小,包括:
- 处理器寄存器的宽度。
- 地址的宽度。
- 数据总线的宽度。
- 算术逻辑单元的宽度。
暂时假设所有这些都是64位。即使如此,为什么我们要求例如
uint32_t
对齐到64位呢?
要求对齐的一个原因是为了避免在内存传输中分割访问。如果总线宽度为64位,则系统通常设计为以8个字节(64位)的倍数访问内存。当处理器想要读取某些内存,例如从64位地址读取时,它只发送前61位到内存设备。 (61很多,但我们已经假设这台机器上的所有东西都是64位)。 内存设备获取与这61位匹配的所有八个字节,即我们未发送的低三位的八个组合。它每次获取八个字节,因为这是适合总线的,并且我们希望效率高。
因此,每当进程从内存中读取时,它总是会获取八个字节,并且这些字节将是64位对齐的。
现在我们可以看到,如果
uint32_t
从某个地址开始,例如xxx0101,其中x表示我们不关心的位,那么它的四个字节将在地址xxx0101、xxx0110、xxx0111和xxx1000。但是第四个字节在八个字节中的另一组。前三个都在同一组中,由初始位xxx0寻址的组。最后一个字节在新组xxx1中。为了读取这个
uint32_t
,我们必须从内存中进行两次读取。这是低效的。
但是,如果
uint32_t
位于地址xxx0000或xxx1000中,则其字节都在一个组内。它们可能是该组中的前四个或后四个字节,因此我们需要处理器能够从内存中选择前四个或后四个字节,但只需要从内存中读取一次即可获取字节。
因此,对于
uint32_t
,四字节对齐就足以确保它对齐得足够好,我们只需要从内存中读取一次即可获取它。
很少需要要求8字节对齐。一个原因是,如果它是8字节对齐的,我们就不需要处理器中额外的电线和开关来选择8个字节中的前4个或后4个字节。我们只需要取前4个。但这种微小的优势远远被这样一个事实所淹没:这意味着我们每8个字节只能存储一个
uint32_t
。一半的内存将被浪费用于填充。使用4字节对齐,我们可以很好地读取
uint32_t
对象,并且可以同时读取两个。
对于
uint8_t
,8字节对齐甚至更糟糕,我们每8个字节只能有一个
uint8_t
,浪费了87.5%的内存。
大多数情况下,长度为
n字节的对象只需要具有
n字节对齐才能与硬件良好配合(假设
n是2的幂)。该对齐方式将使它们完美地适应总线和内存操作,无论它们的宽度如何。
此外,如果总线宽度为
b,对象大小为
n,则对齐要求可能只是
b或
n中较小的一个。一旦一个对象大于总线宽度,我们将需要多次传输才能获取它,并且通常不需要比总线宽度更高的对齐方式。
uint8_t
成员,你会更加惊讶的... - undefined-m64
参数得到相同的结果。 - undefined