好的,我可能在这里完全不合时宜,因为这有点超出我的范围。如果是这样,请纠正我。但这就是我的看法:
首先,为什么我们需要填充和对齐?这只是浪费字节,不是吗?好吧,事实证明处理器喜欢它。也就是说,如果您向 CPU 发出一条对 32 位整数进行操作的指令,CPU 将要求该整数驻留在可被 4 整除的内存地址中。对于 64 位整数,它需要驻留在一个可被 8 整除的地址。等等。这样做是为了使 CPU 设计更简单,性能更好。
如果您违反此要求(也称为“未对齐的内存访问”),大多数 CPU 将引发异常。x86 实际上是一个奇怪的东西,因为它仍然会执行操作 - 但它会花费两倍以上的时间,因为它将通过两次而不是一次从内存中获取值,然后执行按位魔法将值从这些单独的访问中粘在一起.
所以这就是编译器向结构添加填充的原因 - 以便所有成员都正确对齐并且 CPU 可以快速(或根本)访问它们。好吧,这是假设结构本身位于正确的内存地址。但是,只要您坚持标准操作来分配内存,它也会解决这个问题。
但是可以明确地告诉编译器您也想要不同的对齐方式。例如,如果你想使用你的结构从一个紧密打包的文件中读取一堆数据,你可以显式地将填充设置为 1。在这种情况下,编译器还必须发出额外的指令来补偿潜在的错位。
TL;DR - 错误的对齐会使一切变慢(或者在某些情况下可能会使您的程序完全崩溃)。
然而,这并没有回答“在哪里更好地放置填充?”的问题。需要填充,是的,但是在哪里?好吧,它直接并没有太大的区别,但是通过仔细重新排列您的成员,您可以减小整个结构的大小。使用更少的内存通常意味着更快的程序。特别是如果您创建这些结构的大型数组,使用更少的内存将意味着更少的内存访问和更有效的 CPU 缓存使用。
但是,在您的示例中,我认为没有任何区别。
PS 为什么你的结构以填充结尾?因为数组。编译器希望确保如果您分配这些结构的数组,它们都将正确对齐。因为数组成员之间没有任何填充。