我知道这段代码永远不应该被执行,但是*(NULL)
按照 C99 标准编译成功了吗?
#include <stdio.h>
int main(void) {
*(NULL);
return 0;
}
PS:在ideone上运行它返回0,但我不知道正在使用的编译器版本:(
如果NULL
定义为简单0
(允许),则*(0)
违反约束,必须进行诊断。如果NULL
定义为((void *)0)
then*((void *)0)
调用未定义的行为(通过取消引用空指针)并且编译器不需要发出任何诊断,但程序也不需要按照您期望的方式运行。
*(NULL)
总是违反约束。*(NULL)
作为一个完整的表达式在 C 中的任何定义下都是“不可编译的” NULL
。NULL
可以定义一个整数零,这显然是不可解引用的。NULL
可以定义为整数零转换为void *
类型,但void *
在 C 中取消引用指针是非法的。
注意:我仍然不完全确定我上面关于取消引用void *
指针的陈述是否正确。是否违反约束?该标准没有明确说明。但同时它只定义了*
指向函数的指针和指向对象的指针的一元行为。同时,void
不是对象类型。
void *
如果取消引用指针确实是合法的,那么*(NULL)
它本身就会产生未定义的行为(假设(void *) 0
定义NULL
)。但仍有一个上下文*(NULL)
可能作为子表达式有效。它是&*(NULL)
。该语言对组合进行了特殊处理&*
,使其成为具有明确行为的无操作,即使在*
单独会产生未定义行为的情况下也是如此。
*(NULL)
是未定义的行为。
从马口:
(C99, 6.5.3.2.p4) “如果一个无效值被分配给指针,一元 * 操作符的行为是未定义的。87)”
并且(强调我的):
87):“一元 * 运算符取消引用指针的无效值包括空指针、与指向的对象类型不恰当对齐的地址,以及对象生命周期结束后的地址。”
当然,NULL
是一个空指针:
(C99,7.17p3)“宏 [..] NULL 扩展为实现定义的空指针常量;”
与调用未定义行为的所有程序一样,编译器有权不编译它(参见 C99,3.4.3p2)。