64 位系统上的指针值范围

Range of pointer values on 64 bit systems

本文关键字:指针 范围 系统      更新时间:2023-10-16

最近我读到了小字符串优化(SSO):libc++中短字符串优化的机制是什么?众所周知,字符串通常由 3 个指针组成,在 64 位系统上是 24 个字节。链接答案说,在libc++的实现中,第一个指针的第一个位用于指示字符串是处于"长"还是"短"模式,即堆分配和外部存储与最多约22个字符的内部存储。

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

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

如果有一些位数,例如 8 或 16 位保证不变,那肯定是以一些有趣的方式利用的。利用这一点会很好,但不能以代码在某些机器上神秘地失败为代价。

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

libc++ 并非如此。"长字符串"的__long结构定义为:

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

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

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

这些限制将来可能会发生变化,并且会因平台而异,因此在独立于平台的标准库中使用它们会很糟糕。通常,最好使用最低有效位进行指针标记,因为应用程序可以控制这些位。

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

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

"诀窍"是,如果您总是分配偶数个字符并为 NUL 终止符保留一个字符,则生成的容量将始终为奇数。您可以免费获得 1 位!