c - 如何使用三元运算符创建 #define 宏,其中一个操作数不执行任何操作?

标签 c macros

我正在阅读“没有错误!”作者:David Thielen,第 3 章讨论了一种确定给定代码路径是否已被命中的方法。它建议使用一个宏来检查参数,如果参数为真,则执行生成特定中断(0x3)的汇编指令以创建调试器断点。如果宏的参数为 false,则它不会执行任何操作。

宏看起来像这样:

#ifdef DEBUG
#define Trap(t)     ( (t) ? __asm__("int $0x3") : )
#endif

但是,此代码会导致 gcc 编译错误:

int_test.c:16:35: error: expected expression before ‘__asm__’

我是从here学到的因为 gcc 的 asm 是 block 语句而不是表达式,所以我必须使用 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 为 false,我不能让预处理器插入任何内容而不使用这种烦人的语法吗?

注意:为了简单起见,我省略了一些其他类似的宏,并且我已经调整了书中的语法以适用于 gcc(例如用 asm 替换本书的 _asm 以及使用 AT&T语法和围绕“”中的汇编)

最佳答案

您从本书中得到的建议本质上是创建您自己的 assert() 功能。

在大多数系统上,您应该只使用 assert.h 中提供的 assert() 宏。如果触发断言并且您在调试器下运行,则断言将触发断点(同样 - 在大多数系统上)。

如果由于某种原因您无法使用标准 assert.h 功能(例如,可能是某种不提供该功能的简单嵌入式系统工具链),您可以这样做像下面这样:

#ifdef DEBUG_MODE
    void DoAssert(void);
    #define ASSERT(expr) ((expr) ? (void) 0 : DoAssert())
#else
    #define ASSERT(expr) ((void) 0)
#endif

并将您需要捕获的任何内容放入 DoAssert() 函数中的调试器中 - 在您的情况下,这将是 int 3 的内联程序集。

关于c - 如何使用三元运算符创建 #define 宏,其中一个操作数不执行任何操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20577065/

相关文章:

c++ - 如何查找变量是在堆栈还是堆中分配?

objective-c - 使用 React Native 的 Native Modules 从 Swift 文件中获取变量?

vim - 您在 Vim 中使用过的最喜欢/最高效的宏是什么?

c - C 中宏中的宏

c++ - 这是使用宏的好方法吗?

c++ - 使用 mmap 和/dev/mem - 可以使用reinterpret_cast吗

c - 我的浮点代码或 gcc 中有错误吗?

c - 在 C 的 while 循环中,我声明了一个 char[..],我是否必须在每次迭代中清除它?

c - C中的 "short int"和 "int"有什么区别?

macros - 强制 Clojure 宏中的参数获取命名空间捕获