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