简短的回答是,处理器中的基本对象的大小为 2 的小幂(例如,1、2、4、8 和 16 字节),并且内存按大小为 2 的小幂(例如,8)的组进行组织。字节),因此结构必须对齐才能很好地适应这些大小。
长的答案是,其原因是基于物理学和初等数学的。计算机自然地使用值为 0 和 1 的位。这是因为设计在两个值之间切换的物理事物很容易:高电压和低电压、存在电荷或不存在电荷等等。区分三个值比较困难,因为您必须对值之间的转换更加敏感。因此,随着计算机技术几十年来的发展,我们已经使用位(二进制数字)来代替三位数字等替代品。
为了得到更大的数字,我们组合多个位。因此两个位组合起来可以有四个值。三位可以有八个值,依此类推。在较旧的计算机中,有时位一次分为六个或十个。然而,八个变得很常见,并且现在基本上是标准的。使用八位作为一个字节并不像我描述的其他一些分组那样具有强大的物理原因,但这是世界的方式。
计算机的另一个特点是内存。一旦我们有了这些字节,我们希望将它们存储在处理器可以轻松访问的设备中,这样我们就可以快速地将大量字节传入和传出处理器。当我们有很多字节时,我们需要一种方法让处理器告诉内存处理器想要读取或写入哪些字节。因此处理器需要一种对字节进行寻址的方法。
处理器使用位来表示值,因此它将使用位来表示地址值。因此,存储器将被构建为接受位来指示处理器读取时向处理器提供哪些字节或处理器写入时存储哪些字节。存储设备如何处理这些位?一件简单的事情是使用一位来控制存储器路径的一个开关。内存将由许多存储字节的小部分组成。
考虑存储设备中可以存储字节的事物,并考虑其中两个彼此相邻的事物,例如 A 和 B。我们可以使用开关来选择是否希望 A 字节处于活动状态或 B 字节处于活动状态。积极点。现在考虑其中的四件事,即A、B、C和D。我们可以使用一个开关来选择是使用A-B组还是使用C-D组。然后另一个开关选择 A 或 B(如果使用 A-B 组)或 C 或 D(如果使用 C-D)组。
此过程继续进行:内存地址中的每一位选择要使用的一组存储单元。 1 位在 2 个存储单元之间选择,2 位在 4 个存储单元之间选择,3 位在 8 个存储单元之间选择,4 位在 16 个存储单元之间选择,依此类推。 8 位在 256 个存储单元之间选择,24 位在 16,777,216 个存储单元之间选择,32 位在 4,294,967,296 个存储单元之间选择。
还有一个复杂的情况。在处理器和内存之间移动单个字节的速度很慢。相反,现代计算机将内存组织成更大的块,例如八个字节。您一次只能在内存和处理器之间移动八个字节。当处理器请求内存提供一些数据时,处理器仅发送地址的高位 - 低三位选择八个字节内的各个字节,并且它们不发送到内存。
这样速度更快,因为处理器获取 8 个字节所需的时间是内存完成所有切换以提供一个字节所花费的时间,而且它更便宜,因为您不需要区分各个字节所需的大量额外开关。内存中的字节。
然而,现在这意味着处理器无法从内存中获取单个字节。当您执行访问单个字节的指令时,处理器必须从内存中读取八个字节,然后在处理器内部移动这些字节以获得所需的一个字节。同样,要获取两个或四个字节,处理器会读取八个字节并仅提取所需的字节。
为了简化这个过程,处理器设计者指定数据应该以某种方式对齐。通常,它们要求将两字节数据(例如 16 位整数)与两个字节的倍数对齐,将四字节数据(例如 32 位整数和 32 位浮点值)与四的倍数对齐字节,以及要与八字节的倍数对齐的八字节数据。
这种必要的对齐有两个效果。首先,由于四字节数据只能从内存读取的八字节块中的两个位置开始(开头或中间),因此处理器设计者只需放置电线即可从两个位置提取四个字节。如果允许任何对齐,他们不需要添加所有额外的连线来从可能作为起始位置的八个单独字节中的任何一个中提取四个字节。 (有些处理器将完全禁止加载未对齐的数据,而有些处理器将允许它,但使用缓慢的方法来提取数据,这些方法使用较少的线路,但使用迭代算法在多个处理器周期内移动数据,因此未对齐的加载速度很慢。)
第二个效果是,由于四字节数据只能在八字节块中的两个位置开始,因此它也在该块内结束。考虑一下如果您尝试加载从八字节块的第六字节开始的四个字节的数据,会发生什么情况。前两个字节位于该块中,但接下来的两个字节位于内存中的下一个块中。处理器必须从内存中读取两个块,从每个块中取出不同的字节,然后将这些字节放在一起。这比只读取一大块要慢得多。
因此,内存是按 2 的幂组织的,因为这是位的自然结果,并且处理器需要对齐,因为这使得内存访问更加高效。对齐自然是 2 的幂,这就是为什么当结构大小是用于对齐的 2 的幂的倍数时效果更好。