指针的数字值

使用 reinterpret_cast 将指针转换为整数的结果是实现定义的,但“……对于那些知道底层机器的寻址结构的人来说,意图是不足为奇的。”

int x = 42;
int* p = &x;
long addr = reinterpret_cast<long>(p);
std::cout << addr << "\n"; // prints some numeric address,
                           // probably in the architecture's native address format

同样,通过从整数转换获得的指针也是实现定义的。

将指针存储为整数的正确方法是使用 uintptr_tintptr_t 类型:

// `uintptr_t` was not in C++03. It's in C99, in <stdint.h>, as an optional type
#include <stdint.h>

uintptr_t uip;

Version >= C++ 11

// There is an optional `std::uintptr_t` in C++11
#include <cstdint>

std::uintptr_t uip;

对于定义 uintptr_t(C99 标准,6.3.2.3),C++ 11 引用 C99:

一个无符号整数类型,其属性是任何到 void 的有效指针都可以转换为这种类型,然后转换回指向 void 的指针,结果将等于原始指针。

同时,为广大现代的平台上,你可以假设一个平面地址空间和 uintptr_t 算术相当于对 char *算术,这是完全有可能实现转换 void *uintptr_t 只要改造时进行任何改造可以逆转从 uintptr_t 回到 void *时。

技术性

  • 在符合 XSI 的(X / Open System Interfaces)系统上,需要 intptr_tuintptr_t 类型,否则它们是可选的

  • 在 C 标准的含义内,函数不是对象; C 标准不保证 uintptr_t 可以保存一个函数指针。无论如何,POSIX(2.12.3) 一致性要求:

    所有函数指针类型应与 void 指向的类型指针具有相同的表示形式。将函数指针转换为 void *不得改变表示。这种转换产生的 void *值可以使用显式转换转换回原始函数指针类型,而不会丢失信息。

  • C99§7.18.1:

    当 typedef 名称仅在缺少或存在初始 u 时定义时,它们应表示 6.2.5 中描述的相应的有符号和无符号类型; 提供这些相应类型之一的实现也应提供另一种。

    uintptr_t 可能是有意义的,如果你想对指针的位做一些你不能用有符号整数明智地做的事情。