空指针是如何实现的?

How are void pointers implemented?

我想知道 void 指针是如何实现的。我试图用 x86-64 在 Godbolt 上找到它(你可以看到它 here),但它没有显示任何内容。 void指针是如何实现的?

编辑: 这是我使用的代码:

int main() {
    int volatile y = 123;
    void* volatile x = &y;
}

我想在这里看到的只是 x 的样子。我放置了 volatile 以便 gcc 不会将其作为死代码消除。

一般来说,x86-64 处理器上的所有指针都只是包含一些内存地址的 8 字节值。只有编译器关心它们指向它的内容。

从我的角度来看,asm 清楚地揭示了 void* 使用与其他指针相同的对象表示,例如 int*,因此向 void* 和从 void* 进行转换是不行的-op 只是让编译器的类型系统开心。

asm 中的所有内容都只是字节,您可以根据需要对其进行整数运算。 指针只是您可以取消引用的整数。例如在 x86-64 asm 中,+1uintptr_t+1char* 没有区别,因为 C 将 sizeof(char) 定义为 1, x86-64 是字节可寻址的,因此指针的每个整数增量都是一个新字节。 (所以 x86-64 上的 C 实现使用 CHAR_BIT=8)。

void* 只是一种可以保存任何指针值的类型,但不允许您使用 +1 或其他任何方法对其进行数学运算。 C 中的 OTOH 你不需要强制转换以分配其他指针类型 to/from 它。


所有这些都来自具有平面内存模型的 x86-64,而不是 seg:off 之类的东西。并且函数指针与数据指针具有相同的表示。在假设的机器(或 C 实现)上,您可能会看到 void*.

的一些特殊内容

例如在字可寻址内存之上模拟 CHAR_BIT=8 的机器可能具有 sizeof(char*) > sizeof(int*),但 void* 必须足够宽以容纳任何可能的指针,甚至可能具有不同的格式比任何一个。 (有一个窄的 char 实际上不能以线程安全的方式存储(没有包含词的非原子 RMW)对于 C11 是不可行的。)

半相关: 谈论 C 指针如何在其他假设的非简单实现中工作。 seg:off 指针模型不会使 void* 不同于 int*

加上上面的答案,内存没有任何类型。一般而言,每个指针类型基本上都是一个无符号长整型值,指向内存中的某个地址。

本来C语言没有void*char*是泛型指针类型。引用 C: A Reference Manual:

the problem with this use of char* is that the compiler cannot check that programmers always convert the pointer type properly