这个陈述的功能是什么*(长*)0 = 0;?

yat*_*dra 35 c c++

在下面的代码中,*(long*)0=0;if子句一起使用,但它的目的是什么?

if(r.wid*r.ht < tot)
    *(long*)0=0;
Run Code Online (Sandbox Code Playgroud)

unw*_*ind 58

它将0写入0解释为a的地址long,即NULL指针.这不是一件有效的事情,因为NULL从来不是一个可以有效获取程序可以访问的数据的地址.此代码触发未定义的行为 ; 一般来说,你不能依靠它产生任何特殊的效果.

但是,通常这样的代码用于强制分段故障类型崩溃,这有时很容易放入调试器.

同样,这是未定义的行为 ; 不能保证它会导致这样的错误,但是在有分段错误的系统上,上面的代码很可能产生一个错误.在其他系统上,它可能会完全不同.

如果你得到段错误,有时候通过这种方式触发比在调试器中手动设置断点更方便.例如,如果您没有使用IDE,那么将这些少量令牌输入到所需位置的代码中往往比向调试器提供(textual)命令更简单,指定确切的源代码文件和行号手动可能有点烦人.

  • 是否有理由支持"断言"? (15认同)
  • 虽然@ unwind的答案对于大多数通用机器来说是完全正确的(并且他正确地指出它是未定义的行为,并且不能保证),但这样的代码确实在嵌入式系统中找到了一个位置,其中确实存在某些东西(内存映射IO,或者地址0处的专用存储器地址(或空指针映射到的任何地址). (12认同)
  • 为什么保证此代码会导致分段错误? (4认同)
  • @Zaibis C99草案说"如果为指针分配了一个无效值,那么一元`*`运算符的行为是未定义的",并澄清它包含`NULL`指针. (3认同)
  • @Damon在我倾向于工作的巨大代码库中,我们倾向于在发布版本中尽可能多地保留*启用*,因为实际上不可能*确定*你不能通过某些代码路径来访问它们尽管质量保证和测试开发做出了最大的努力,但仍然错过了. (3认同)
  • @ user694733它更简单,即它做得更少.可以编译`assert()`,并调用`abort()`,这与在调用站点获取段错误不同. (2认同)

zwo*_*wol 18

在教科书C中,abort是故意使程序崩溃的方法.但是,当您接近金属编程时,您可能不得不担心abort不能按预期工作!abort调用的标准POSIXy实现getpidkill(通过raise)传递SIGABRT给进程,进而可能导致执行信号处理程序,这可以按照自己的意愿执行.有些情况,例如内心深处malloc,以应对灾难性的,可能是对抗性的内存损坏,你需要在不触及堆栈的情况下强制崩溃(具体而言,不执行返回指令,可能会跳转到恶意代码) ). *(long *)0 = 0在这种情况下尝试并不是最疯狂的事情.它仍然存在执行信号处理程序的风险,但这是不可避免的; SIGKILL没有进行函数调用就无法触发.更严重的(恕我直言)现代编译器有点太可能看到它,观察它有未定义的行为,删除它,并删除测试,因为测试不可能永远是真的,因为没有人会故意调用未定义的行为,他们会吗?如果这种逻辑似乎有悖常理,请阅读LLVM小组关于未定义行为和优化讨论(第2 部分,第3部分).

有更好的方法来实现这一目标.现在许多编译器都有一个内在的(例如gcc,clang :) __builtin_trap(),它产生的机器指令可以保证导致硬件故障和交付SIGILL; 与使用指针的未定义技巧不同,编译器不会优化它.如果您的编译器没有那个,但确实有汇编插入,那么您可以手动插入这样的指令 - 这可能是低级别的代码,以至于额外的机器依赖性并不是什么大问题.或者,你可以打电话_exit.这可以说是最安全的方式,因为它不会冒运行信号处理程序的风险,甚至在内部也不涉及函数返回.但这确实意味着你没有获得核心转储.

  • @Shahbaz抱歉,不,中间的`void*`没有任何区别.你错了两个方面:首先,`0`本身就是一个有效的空指针常量,因此`(long*)0`和`(long*)(void*)0`都是*两个*空指针.其次,无论你如何构造空指针,取消引用空指针都会引发未定义的行为. (2认同)
  • @Shahbaz标准与Zack一致:"一个整数常量表达式,其值为0,**或**,这样的表达式转换为void*类型,称为空指针常量." 然后(parens mine):"如果一个空指针常量(`0`,如上所述)转换为指针类型(`long*`),结果指针,称为空指针......" - N1570§6.3 2.3 (2认同)

Ian*_*vey 6

要使程序"异常退出",请使用该abort()功能(http://pubs.opengroup.org/onlinepubs/9699919799/functions/abort.html).

标准的C/C++习语是"如果条件X不正确,使程序异常退出"是assert()宏.上面的代码会写得更好:

assert( !(r.wid*r.ht < tot) );
Run Code Online (Sandbox Code Playgroud)

或者(如果你很乐意忽略边缘情况),它会更清晰地读取:

assert( r.wid*r.ht >= tot );
Run Code Online (Sandbox Code Playgroud)