首页 文章

禁用gcc中的“if(0)”消除

提问于
浏览
18

如何防止GCC消除 if(0) 块内的代码?

当我使用Visual Studio时,我的一种调试技巧是将这样的代码放在我的程序中:

if (0)
    do_some_debug_printing_and_checking();

然后,当一个断点被击中时,我点击 do_some_debug_printing_and_checking() 行,选择"set next statement"并强制它执行 .

当我使用gcc / gdb作为后端时,"set next statement"不再起作用,因为GCC只是从 if(0) 语句中删除代码 .

我当然使用 -O0 标志来禁用优化 . 我也尝试了 -fno-dce -fno-tree-dce 标志来显式禁用死代码消除,但它没有效果: if(0) 的内容在二进制文件中不存在,我不能使用 set next statement 跳转到它 .

有没有什么好方法告诉gcc禁用 if(0) 内容的删除?

编辑:

感谢“附加变量”解决方法,但有两件事我不喜欢它:

  • 这还是一行额外的代码

  • 它赢得了更多的额外线条 .

真的,绝对没有选择让GCC保留死代码吗?

2 回答

  • 8

    最简单的方法是使检查依赖于(比如)具有外部链接的变量 .

    例如 .

    extern bool debug;
    if (debug)
        do_some_debug_printing_and_checking();
    

    在命名空间范围的某处:

    bool debug = false;
    
  • 12

    我不会依赖gcc编译器标志来做到这一点 . 编译器标志可以在gcc版本之间进行更改,并且可以在编译器之间进行更改 . 您可能会发现自己需要在Visual C中六个月内调试相同的代码...

    @CharlesBailey对如何使用 extern 变量做了一个很好的建议 . 这里's one alternative that doesn' t要求变量暴露给整个模块或保存在静态存储中 .

    if 语句的范围内声明临时变量 volatile

    if (volatile bool dbg = false)
    {
      do_some_debug_printing_and_checking();
    }
    

    这使临时变量的范围非常窄 . volatile 限定符不允许编译器假设有关变量的任何内容,或者优化分支 .

    要记住的一件事是变量总是在堆栈上分配,并且将保留在堆栈中,直到函数退出 . 这种方法和 extern 方法都应该有效,但是有一些不同(可能是可以忽略不计)的权衡 .

    如果您愿意使用宏来帮助解决此问题,那么在将代码发布到 生产环境 环境中时,可以轻松禁用临时变量:

    #ifndef IS_DEBUGGING
    #  define IS_DEBUGGING 0
    #endif
    
    #if IS_DEBUGGING
    #  define TMP_DBG_FLAG volatile bool dbg_flag = false
    #else
    #  define TMP_DBG_FLAG false
    #endif
    

    然后将 if 声明声明为:

    if ( TMP_DBG_FLAG )
    {
      do_some_debug_printing_and_checking();
    }
    

    将IS_DEBUGGING定义为1时,将创建局部变量,声明为volatile并保留 . 当您将IS_DEBUGGING定义为0时,宏将扩展为常量 false ,并且编译器会优化分支 . 也可以为 extern 方法做一些非常相似的事情 .

    这几行额外的代码,但它们与您使用TMP_DBG_FLAG的次数无关 . 该代码比使用大量的 ifdef 更易读 . 可以使宏更安全(通过向它附加 __LINE__ 的值),但这需要三个宏,并且可能不是必需的:

    #if IS_DEBUGGING
    // paste symbols 'x' and 'y' together
    #  define TMP_DBG_FLAG_SYMCAT0(x,y) x ## y
    
    // need one level of indirection to expand __LINE__...
    #  define TMP_DBG_FLAG_SYMCAT(x,y) TMP_DBG_FLAG_SYMCAT0(x,y)
    
    #  define TMP_DBG_FLAG volatile bool TMP_DBG_FLAG_SYMCAT(dbg_flag_,__LINE__) = false
    #else
    #  define TMP_DBG_FLAG false
    #endif
    

相关问题