【问题标题】:Range of pointer values on 64 bit systems64 位系统上的指针值范围
【发布时间】:2016-04-19 00:04:32
【问题描述】:

最近我在阅读有关小字符串优化 (SSO) 的文章:What are the mechanics of short string optimization in libc++?。众所周知,一个字符串通常由 3 个指针组成,在 64 位系统上为 24 个字节。链接的答案说,在 libc++ 的实现中,第一个指针的第一位用于指示字符串是处于“长”还是“短”模式,即堆分配和外部存储与最多 22 个字符的内部存储.

然而,这假设第一个指针的第一位永远不可能有意义地成为地址的一部分,因为每当字符串处于“长”模式时,该位将始终设置(或取消设置,具体取决于选择的约定) )。从表面上看,这似乎是合理的,因为 64 位指针允许 2^64 个地址,大于 1 后跟 18 个字节的零,或超过 10 亿 GB。

所以这是合理的,尽管不确定。我的问题是:这在某处有保证吗?如果有保证,在哪里保证?通过架构规范,还是通过其他方式?更进一步:使用多少位是安全的?我有一个模糊的回忆,在某处只使用了 48 位,但我不记得了。

如果有一些位数,例如8 或 16 保证不会受到影响,这肯定是可以通过一些有趣的方式加以利用的东西。利用这一点会很好,但不会以在某些机器上出现代码神秘故障为代价。

【问题讨论】:

  • Itanium 和 Alpha 是非常不同的平台。您能做的最好的事情就是说明操作系统使用的内存布局。
  • @ Flexo 好吧,这已经是部分答案了,如果安腾规范对此有话要说,那么这就是一个开始。
  • 已经投票关闭?我能问为什么吗?
  • 它更有可能是最不重要位,而不是位。长字符串缓冲区将从堆中分配,并且几乎可以肯定是 8 字节对齐(至少),因此底部四位为零。这样可以避免对整体内存布局做出任何假设。
  • 您在多个方面都犯了错误。短字符串标志根本不与指针重叠,它与保存长字符串的 size 的字段重叠。即使它确实与指针重叠,它也会是指针的低位,这意味着内存 range 不会进入它,只是对齐。

标签: c++ c pointers


【解决方案1】:

众所周知,一个字符串通常由 3 个指针组成,在 64 位系统上为 24 个字节。

这不适用于 libc++。 __long 结构,对于“长字符串”定义为:

struct __long
{
    size_type __cap_;
    size_type __size_;
    pointer   __data_;
};

因此,短标志进入容量字段,使整个事情变得毫无意义。

对于指针标记,指针的大小没有通用的保证。在 x86_64 上,CPU 用于虚拟地址转换的数据结构仅使用 48 位(或物理地址扩展的 52 位),因此虚拟地址从不使用高 16(或 12)位。此外,大多数操作系统将其内核映射到每个进程并为其保留一些高端地址空间,因此在实践中,用户模式指针受到更多限制。在 Windows 上,指针的最重要的硬件可用位告诉它属于内核空间还是用户空间。

这些限制将来可能会发生变化,并且会因平台而异,因此在独立于平台的标准库中使用它们是一种不好的形式。一般来说,use the least-significant bits for pointer tagging 是更好的做法,因为您的应用程序可以控制这些。

【讨论】:

  • 其实x86-64有规范地址,所以高16位是47位的副本,所以可以设置。
  • @EOF 那么这有保证吗?如果是这种情况,那么听起来实际上可以将这些位用于某些事情,并在取消引用之前简单地设置前 16 位。
  • @NirFriedman:是的,规范指针由硬件强制执行,如果您尝试取消引用非规范地址,则会出现异常。但是,如果虚拟地址空间在未来几代处理器中扩展,依赖于那些未被使用的位的代码将不再工作。我很确定规范地址应该阻止这种使用。
【解决方案2】:

“长位”不是指针的一部分,而是容量的一部分:

struct __long
{
    size_type __cap_;
    size_type __size_;
    pointer   __data_;
};

“诀窍”是,如果您始终分配偶数个字符并为 nul 终止符保留一个,则结果容量将始终为奇数。并且您可以免费获得 1 位!

【讨论】:

  • 感谢您指出这一点,我愚蠢地认为字符串使用了 3 个指针,就像 vector 通常一样,绝对是个脑残。我接受了 zneak 的回答,因为他添加了有关我问题核心的更多信息,但也感谢您!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-02-04
  • 1970-01-01
  • 1970-01-01
  • 2019-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多