所以问题中的代码行是:
*((int*)(0))=1;
因为我对C/C++几乎没有经验,也没有尝试过很多,所以我不理解这个简单的表达式。它到底是什么意思?
它的意图是让程序崩溃,在调试期间非常有用。
它将取消引用空指针并尝试向该内存分配一个值,这在理论上只是未定义行为,但在99%的系统中会导致访问冲突异常。
通常,它出现在以下情况下:
if ( !FileRead(importantFile) )
{
// this should never happen, critical exception
*((int*)(0))=1;
}
逐个分解。在左侧的外部括号中,您有:
(int*)(0)
这是将值0进行C语言样式的类型转换,转换为指向整型的指针,从而创建了一个空指针。
现在我们添加一个变量来接收第一个表达式的结果:
int* x = (int*)(0);
现在外部部分为:
*(x) = 1;
这里是对指针x进行解引用,然后将结果赋值为1。
由于(在这种情况下)x是一个空指针,这将导致解引用崩溃(严格来说,会在解引用后面的赋值时崩溃 - 请参见下面的评论)。通常用于强制崩溃或其他与系统相关的未定义行为; 通常用于测试或调试目的。在生产代码中不应该有像这样的代码。
注意:有些架构,通常是嵌入式系统中,其中零是有效的内存地址,并且上述代码可能具有合法的目的。但是,如果您正在这样的平台上工作,则不太可能在问题的语法方面遇到困难。
raise()
,来自<signal.h>
或<csignal>
。即使在允许写入零地址的计算机(这样的机器确实存在!)和对未定义行为有宽松解释的编译器上,raise(SIGSEGV)
也将产生与您的示例意图相同的结果。该操作不保证崩溃。从编译器的角度来看,它可能什么都不做,从编译后的程序中删除它也不会有错。man signal
。可能意味着raise(SIGTRAP)
或abort()
。在我的系统上,后者等同于raise(SIGABRT)
,但我懒得检查这种等价性是否由POSIX或C语言保证。这个*((int*)(0))=1;
等同于
int *p=NULL;
*p=1;
这将在空指针处存储某些东西(并导致SEGFAULT)。 这对于停止程序并调用调试器以保留所有内存内容等非常有用。
exit(EXIT_FAILURE);
更好在调试时(使用gdb
)会显示消息“程序以退出码 [EXIT_FAILURE] 退出”。 - 0xF1raise()
是更好的选择。 - Potatoswatterabort()
。关于原帖中的问题,将值分配给 NULL 指针是未定义行为;因此,编译器可以推断该行代码会导致未定义的行为,并将其完全优化掉。 - peppe