在下面的代码中,*(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)命令更简单,指定确切的源代码文件和行号手动可能有点烦人.
zwo*_*wol 18
在教科书C中,abort
是故意使程序崩溃的方法.但是,当您接近金属编程时,您可能不得不担心abort
不能按预期工作!abort
调用的标准POSIXy实现getpid
和kill
(通过raise
)传递SIGABRT
给进程,进而可能导致执行信号处理程序,这可以按照自己的意愿执行.有些情况,例如内心深处malloc
,以应对灾难性的,可能是对抗性的内存损坏,你需要在不触及堆栈的情况下强制崩溃(具体而言,不执行返回指令,可能会跳转到恶意代码) ). *(long *)0 = 0
在这种情况下尝试并不是最疯狂的事情.它仍然存在执行信号处理程序的风险,但这是不可避免的; SIGKILL
没有进行函数调用就无法触发.更严重的(恕我直言)现代编译器有点太可能看到它,观察它有未定义的行为,删除它,并删除测试,因为测试不可能永远是真的,因为没有人会故意调用未定义的行为,他们会吗?如果这种逻辑似乎有悖常理,请阅读LLVM小组关于未定义行为和优化的讨论(第2 部分,第3部分).
有更好的方法来实现这一目标.现在许多编译器都有一个内在的(例如gcc,clang :) __builtin_trap()
,它产生的机器指令可以保证导致硬件故障和交付SIGILL
; 与使用指针的未定义技巧不同,编译器不会优化它.如果您的编译器没有那个,但确实有汇编插入,那么您可以手动插入这样的指令 - 这可能是低级别的代码,以至于额外的机器依赖性并不是什么大问题.或者,你可以打电话_exit
.这可以说是最安全的方式,因为它不会冒运行信号处理程序的风险,甚至在内部也不涉及函数返回.但这确实意味着你没有获得核心转储.
要使程序"异常退出",请使用该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)
归档时间: |
|
查看次数: |
3412 次 |
最近记录: |