【问题标题】:Do 4byte aligned pointers use any padding?4字节对齐的指针是否使用任何填充?
【发布时间】:2012-03-05 13:31:30
【问题描述】:

我最近偶然发现了一个“hacky”答案(this one),其中提到因为(我假设是 32 位)C/C++ 指针通常是 4 字节对齐的,每个指针的最后 2 位始终为零。我不明白为什么会这样。为什么不使用所有 32 位来表示一个地址?

请忽略我上面链接的实际答案的优点。我只对关于 2 个 LSB 的观察感兴趣。

【问题讨论】:

  • 最近的 JVM 实际上利用了这一点(参见 CompressedOops)——因为他们知道这些位将为零,所以他们可以使用 32 位指针移位来寻址超过 2^32 字节的内存。但他们可以保证这些位始终为零,在大多数情况下,这可能比您节省的内存更麻烦。
  • 您确实使用所有 32 位来表示地址。但由于地址始终是 4 的倍数,因此地址的最后两位始终为零。与十进制相同。如果您的数字始终是 10 的倍数,则最后两位数将始终为零。
  • 为什么地址总是4的倍数?实现 4 字节对齐只需要 2 的倍数。那么,为什么不使用所有 32 个可用位来存储指针地址呢?

标签: c++ pointers memory-alignment


【解决方案1】:

您可能会注意到该语句中的关键字“通常”。 “通常”并不意味着“总是”。如果某些事情并不总是正确的,你不能假设它是正确的,而只是砍掉最后两位。

大多数指向活动对象的指针将具有至少 4 个字节的对齐方式。但是,您可以创建一个 chars 数组,这些元素将是字节可寻址的。 99% 的时间发生的事情并不意味着您可以忽略没有发生的最后 1%。

大多数指针至少对齐到 4 个字节的原因是大多数指针是指向对象或基本类型的指针,它们本身至少对齐到 4 个字节。具有 4 字节对齐的内容包括(对于大多数系统):intfloatbool(是的,真的)、任何指针类型以及任何其大小或更大的基本类型。

包含其中之一的任何对象必须至少与该对象的对齐方式对齐。因此,存储int 的对象对齐到 4 个字节。包含指针的对象至少对齐 4 个字节。等等。很少有不包含这些基本类型之一的对象。

这就是为什么。您要指向的绝大多数数据类型至少有 4 个字节对齐。

【讨论】:

  • 稍微扩展一下:字对齐的根本原因是它允许更快的访问(例如,在许多 CISC 处理器上)或 CPU 需要(主要在 RISC 设计上),通常很简单因为读取跨越多个单词的值需要您阅读所有这些单词。因此,将值保持在最少字数中可以节省内存成本。
  • 嗨,尼科尔。这没有回答我的问题:我没有问为什么指针通常是 4 字节对齐的,但为什么通常只使用 32 个可用位中的 30 个。
  • @Daniel:一个导致另一个。如果您的指针指向的大部分内容是 4 字节(或更大)对齐,那么这就是您通常不使用的 2 位。指针本质上指向内存中的字节地址。如果它们指向 4 字节边界上的东西,那么它们的值是 4 的倍数。所以最后两位总是为零。因此它们没有被使用。
  • 尼科尔:我还是不明白。你能举个例子,或者给我一个可以进一步解释这个的资源吗?我知道所指向的数据是 4 字节对齐的,但是将可用地址限制为 4 的倍数似乎是不必要的限制。例如,假设我有 16 位内存,而我的分配器通常(并非总是)处理 4 位数量。然后,我可以有一组地址,例如:4、8、12、16——这很好,而且都是 4 的倍数。但是如果保留第一位呢?那么我的可用地址可能类似于:5、9、13。不是 4 的倍数!
  • Daniel:“但将可用地址限制为 4 的倍数似乎是不必要的限制。” “限制”这个词意味着一种限制,一种不可能发生的事情。重新阅读我的第一段,其中我明确声明指针可以指向4字节对齐之外的东西。 “通常”并不意味着总是。至于您的示例,如果您反转第一位,那么您现在拥有的指针并未指向您认为的指针。这与将任意数字添加到指针没有什么不同;它不再像您认为的那样发展了。
【解决方案2】:

如果您指向的地址都是四字节对齐的,那么就不会有任何地址不是四的倍数,或者换句话说,两个最低位将始终为零。因此,您可以极其粗暴地将它们用于其他目的。

【讨论】:

    猜你喜欢
    • 2017-09-27
    • 2020-01-11
    • 1970-01-01
    • 2015-09-02
    • 1970-01-01
    • 1970-01-01
    • 2016-04-22
    • 2017-10-23
    • 1970-01-01
    相关资源
    最近更新 更多