【发布时间】:2014-01-01 20:17:19
【问题描述】:
我正在阅读“没有错误!” David Thielen 和第 3 章讨论了一种确定给定代码路径是否已被命中的方法。它建议使用宏来检查参数,如果为真,则执行生成特定中断 (0x3) 的汇编指令以创建调试器断点。如果宏的参数为假,则它什么也不做。
然后,宏看起来像这样:
#ifdef DEBUG
#define Trap(t) ( (t) ? __asm__("int $0x3") : )
#endif
然而,这段代码会导致 gcc 的编译错误:
int_test.c:16:35: error: expected expression before ‘__asm__’
我从here 了解到,因为gcc 的asm 是块语句而不是表达式,所以我必须使用statement expressions 才能以这种方式使用asm。所以,现在变成了:
#define Trap(t) ( (t) ? ({ __asm__("int $0x3"); }) : )
编译器仍然报错:
int_test.c:16:64: error: expected expression before ‘)’ token
好的,所以现在我必须这样做?
#define Trap(t) ( (t) ? ({ __asm__("int $0x3"); }) : ({ ; }) )
这看起来真的很愚蠢。如果t 为假而不使用这种烦人的语法,我不能让预处理器不插入任何内容吗?
注意:为了简单起见,我省略了一些其他类似的宏,并且我已经调整了书中的语法以适用于 gcc(例如将书中的 _asm 替换为 asm 以及使用 AT&T语法和在 "") 中包围程序集
【问题讨论】:
-
如果只需要副作用而不需要值,为什么要使用三元运算符而不是 if 语句?
-
+1 以使用
if而不是三元运算符。 但是我不得不问,你到底为什么要使用汇编指令来触发断点,而不是仅仅使用真正的调试器并在感兴趣的地方设置断点?这似乎是一种非常、非常原始、不必要、低级且彻头彻尾的古老调试方法...... -
传统上这是通过逗号运算符完成的。例如。 cond && (function_with_side_effects(), 1) 虽然我不确定这是否适用于 GCC 内联汇编语句,因此您可能需要将实际断点放在单独的函数中。有什么特别的原因你不想把整个东西变成一个(内联)函数?
-
@David Norris:它不是普通交互式断点的替代品,而是一个有用的补充。它们通常或多或少地用作断言,除了不一定是错误的条件(例如,突出很少使用的代码路径)
-
@DavidNorris 如果我只使用调试器,每次运行 gdb 时都必须手动设置断点,对吗?除非有办法保存 gdb 配置文件或其他东西。无论哪种情况,我都只是想从这本书中学习,但它是 92 年出版的,所以我猜它已经过时了。