NULL 常量的整数表示:保证是唯一的?

Integer representation(s) of NULL constant: Guaranteed to be unique?

这是一个 "according to the very words of the C-Standard"-问题。是否可以保证从 NULL 转换为无符号整数(大到足以容纳任何指针)会产生相同的值,无论指针的类型如何,它都保持 NULL?

请看下面的一段代码,其中T1、T2可以是C中可构造的任何类型:

#include <stddef.h>

/* unsigned int be known to be big enough to hold any object pointer */
unsigned int ui_ptr1, ui_ptr2, ui_ptr3, res;

ui_ptr1 = (unsigned int) NULL;
ui_ptr2 = (unsigned int) (T1 *) NULL;
ui_ptr3 = (unsigned int) (T2 *) NULL;

res = (ui_ptr1 == ui_ptr2) && (ui_ptr1 == ui_ptr3);

对于任何 T1 和 T2,res 是否保证为 1? 从 ISO:9899:1990 (C90) 我知道,NULL 等同于实现定义的空指针常量 (7.1.6)。而且我知道从给定的指针类型转换,然后再返回是明确定义的,但值是实现定义的。 (6.3.4; G.3.7, 2. "-").

但是我找不到关于上述的任何论据。我错过了什么吗?在更多... 最近的... C 标准迭代中是否有更多保证?

背景: 我想通过一些静态变量通过无符号整数(我在这里别无选择)在函数之间传输指针,需要由 3. 实例正确初始化。初始化实例不知道要传输的指针的类型,因此它需要用一个整数常量(没有转换演变)进行初始化,然后表示 a/the 正确的 NULL 指针常量。如果不是未定义的行为是潜伏的,当我尝试用它做任何事情时。 (另请参阅:)。

来自 C99 和 C11,6.3.2.3 p3:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. 55) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

和 p4:

Conversion of a null pointer to another pointer type yields a null pointer of that type. Any two null pointers shall compare equal.

(此外,脚注 56/67 指出 "The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment")。

(C89 草案与上面第 3.2.2.3 节中引用的 C99 具有等效文本)。

因此,在具有线性寻址方案且指针大小等于字长的体系结构上,可以相当安全地假设单个整数值表示 NULL - 特别是如果你去通过 void * 类型。但理论上,NULL 指针(甚至 void *)在转换为整数时可能不等于 0,因为这不是强制性的。您可以通过在比较值是否表示 NULL.

之前始终通过 void * 进行转换来解决此问题

也就是说,如果您将上述 ui_ptr2 和 ui_ptr3 的声明更改为:

ui_ptr2 = (unsigned int) (void *) (T1 *) NULL;
ui_ptr3 = (unsigned int) (void *) (T2 *) NULL;

...那么你至少可以确定每一个:

(void *) ui_ptr2 == (void *) ui_ptr3
(void *) ui_ptr2 == NULL
(void *) ui_ptr3 == NULL

...将是真实的。如果您将 (void *) ui_ptr2(void *) ui_ptr3 转换为其他指针类型,它仍应为 NULL,根据上面引用的 6.3.2.3 p4。

但是,您依赖指针到整数的转换是可逆的。转换是在两个方向上定义的实现,尽管人们希望将指针转换为整数然后再转换回指针会产生原始指针值,但这并不是严格要求的(尽管上面引用的脚注 56 强烈建议暗示它) .此外,不能保证所有可能的指针值都可以用 any 整数类型表示 (6.3.2.3 p6)。解决此问题的唯一真正方法是验证 sizeof(int) >= sizeof(void *),然后使用 memcpy 将指针的表示形式转移到整数,然后返回,在这种情况下,不再需要通过 void *(只要您存储的指针类型与您检索的类型相同即可)。