标准是否定义空指针常量以将所有位设置为零?

(我引用的是ISO / IEC 9899:201x)

在这里我们看到,整数常量表达式有一个整数类型:

6.6常量表达式

6. 整数常量表达式应具有整数类型,并且只能具有整数常量的操作数,枚举常量,字符常量,结果为整数常量的sizeof表达式,_Alignof表达式以及作为强制转换的直接操作数的浮点常量。 整数常量表达式中的转换运算符只能将算术类型转换为整数类型,除非作为sizeof或_Alignof运算符的操作数的一部分。

这适用于任何整数类型:

6.2.6.2整数类型

5.未指定任何填充位的值。符号位为零的有符号整数类型的有效(非陷阱)对象表示是相应无符号类型的有效对象表示,并且应表示相同的值。 对于任何整数类型,所有位为零的对象表示应该是该类型中零值的表示。

然后我们看到使用值为0的整数常量表达式定义空指针常量。

6.3.2.3指针

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

因此,空指针常量必须将其所有位设置为零。

但是在线和StackOverflow上有许多答案说这不是真的。

考虑到引用的部分,我很难相信他们。

(请使用最新标准的参考答案)

不,NULL不必都是零位。

N1570 6.3.2.3指针第3段:

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

请参阅上面的重点:如果需要,将转换整数0 ,它不必具有相同的位表示。

页面底部的注66说:

66)宏NULL在(和其他头部)中定义为空指针常量; 见7.19。

这导致我们看到该章的一段:

宏是

空值

它扩展为实现定义的空指针常量

而且,附件J.3.12(可移植性问题,实现定义的行为,库函数)说:

– 宏NULL扩展的空指针常量(7.19)。

标准是否定义空指针常量以将所有位设置为零?

不,它没有。 C标准的任何段落都没有强加这样的要求。

 void *p = 0; 

例如, p是一个空指针,但标准不要求对象p必须设置所有位。

有关信息,c-faq网站提到了一些非零空指针表示的系统: http : //c-faq.com/null/machexamp.html

询问空指针常量的表示是没有意义的。

空指针常量具有整数类型或类型void *。 无论是什么,它都是一种价值 。 它不是一个对象。 值没有表示,只有对象具有。 我们只能通过获取对象的地址,将其转换为char *或unsigned char *以及查看字节来讨论表示。 我们不能用空指针常量来做到这一点。 一旦将其分配给对象,它就不再是空指针常量。

C标准的一个主要限制是,因为作者希望避免禁止编译器以任何方式表现出任何地方可能依赖的任何生产代码,所以它无法指定程序员需要知道的许多东西。 因此,通常需要对标准未指定的事物做出假设,但要匹配常见编译器的行为。 包含空指针的所有字节都为零的事实是一个这样的假设。

除了每种数据类型的每个可能值(包括指针)都可以表示为char值序列(*)之外,C标准中没有任何内容指定任何指针的位级表示。 尽管如此,在几乎所有常见平台上,将与结构相关联的所有字节清零都等同于将所有成员设置为其类型的静态默认值(指针的默认值为null)。 此外,使用calloc为结构集合接收零块RAM的代码通常比使用malloc代码快得多,然后必须手动清除每个结构的每个成员,或者使用calloc但仍然手动清除每个结构的每个非整数成员。

因此,我建议在很多情况下编写针对C语言的代码是完全合理的,其中空指针存储为全字节零,并且具有文档要求,它不适用于不是案子。 也许有一天,ISO将提供一种标准方法,通过这种方式可以以机器可读的forms记录这些要求(这样每个编译器都需要遵守程序规定的要求或拒绝编译),但据我所知还没有存在。

(*)根据我的理解,对于编译器是否需要遵守该假设存在一些疑问。 例如,考虑一下:

 int funcomp(int **pp, int **qq) { int *p,*q; p = (int*)malloc(1234); *pp = p; free(p); q = (int*)malloc(1234); *qq = q; *q = 1234; if (!memcmp(pp, qq, sizeof p)) return *p; return 0; } 

free(p)任何访问*p尝试都将是Undefined Behavior。 尽管q将很有可能获得与p完全相同的位模式,但标准中没有任何内容要求p必须被视为q的有效别名,即使在该场景中也是如此。 另一方面,同样类型的两个变量可以保持完全相同的位而其内容不相等也似乎很奇怪。 因此,虽然很明显很自然地允许该函数返回0以及*pp*qq值,这些值不比较逐位相等,或者1234以及*pp*qq值比较位如果两个malloc碰巧产生按位等效值,则标准似乎允许函数任意行为。