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

时间:2015-07-10 09:06:56

标签: c pointers null c89

这是一个"根据C-Standard" -Question的话。是否保证,从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。&#34; - &#34;)。

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

背景 我想通过一个无符号整数(我在这里没有选择)通过一些静态变量传输函数之间的指针,需要通过3.实例初始化。初始化实例不知道要传输的指针的类型,因此需要使用整数常量进行初始化(不进行转换),然后表示/正确的NULL指针常量。如果没有未定义的行为潜伏,当我尝试用它做任何事情。 (另见:Allowed operations on an possibly invalid pointer by the strict interpretation of the C Standard)。

1 个答案:

答案 0 :(得分:3)

从C99和C11,6.3.2.3 p3:

  

值为0的整型常量表达式,或者类型为void *的表达式,称为空指针常量。 55)如果将空指针常量转换为指针类型,则保证将结果指针(称为空指针)与指向任何对象或函数的指针进行比较。

并且p4:

  

将空指针转换为另一种指针类型会产生该类型的空指针。任何两个空指针都应该相等。

(另外,脚注56/67说明&#34;用于将指针转换为整数或整数到指针的映射函数旨在与执行环境的寻址结构一致&#34;)。

(C89的草案与上文第3.2.2.3节中引用的C99具有相同的文字。)

因此,假设在具有线性寻址方案的架构上以及指针大小等于字大小的情况下,单个整数值代表NULL似乎是相当安全的 - 特别是如果您通过void *类型。但理论上,转换为整数时,NULL指针(偶数void *)可能不等于0,因为它没有强制要求。您可以通过在比较值是否代表void *之前始终转换NULL来解决此问题。

也就是说,如果您将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强烈建议它暗示)。此外,无法保证所有可能的指针值都可以在任何整数类型(6.3.2.3 p6)中表示。您唯一真正的方法是验证sizeof(int) >= sizeof(void *),然后使用memcpy将指针的表示形式转移到整数,然后返回,在这种情况下,不再需要通过{ {1}}(只要您存储的指针类型与您检索的类型相同)。