如果0在c程序中编译

if 0 is compiled in c program

我正在尝试从我的程序中删除未使用的代码 - 我现在无法删除代码,我只想先禁用它。

假设我有以下代码:

if (cond){
  doSomething()
}

cond 始终为假,因此永远不会调用 doSomething

我想做类似的事情:

#define REMOVE_UNUSED_CODE 0
if (cond && REMOVE_UNUSED_CODE){
  doSomething()
}

现在这对我们(希望对编译器)来说很明显,这段代码未被使用。

编译器会删除所有这些 if 条件,还是会留下它永远不会进入?

P.S.: 我不能将 #if 0 用于此目的

查看您的这段代码

#define REMOVE_UNUSED_CODE 0

if(cond && REMOVE_UNUSED_CODE)
{
    doSomething();
}

REMOVE_UNUSED_CODE 在编译前被预处理器替换为 0。 因此 if(cond && 0) 将始终被评估为 false 并且永远不会被执行。所以你可以说,不管 cond 是什么,它总是假的。

所以我更喜欢这样做:

//#define REMOVE_UNUSED_CODE 0

#ifdef REMOVE_UNUSED_CODE
    if(cond)
    {
        doSomething();
    }
#endif

答案取决于编译器的实现。你永远不应该依赖这个。

而是明确:

#define REMOVE_UNUSED_CODE 0
if (cond && REMOVE_UNUSED_CODE){
#ifndef REMOVE_UNUSED_CODE  
   doSomething()
#endif
}

尝试

#ifndef REMOVE_UNUSED_CODE
if (cond) {
   doSomething();
}
#endif

相反。 别忘了做一个

#define REMOVE_UNUSED_CODE

某处。

你不应该那样做:

假设你有一个函数 bool f(void* input) 有副作用。

然后

if( f(pointer) && false ) { ... }

正文未评价,但f应该

的情况下
if( false && f(pointer) ) { ... }
由于 && 运算符的快捷规则,

f 未被计算。

如果你使用

#define REMOVE_UNUSED_CODE
#ifndef REMOVE_UNUSED_CODE
if( f(pointer) && false ) { }

#endif

整个代码甚至没有编译进去,也永远不会执行。

GCC 将显式删除具有控制它们的常量表达式的条件块,并且 the GNU coding standards explicitly recommend that you take advantage of this,而不是使用更粗糙的方法,例如依赖预处理器。尽管使用预处理器 #if 可能看起来更有效,因为它在早期阶段删除了代码,但实际上,现代优化器在您为它们提供尽可能多的信息时效果最好(当然,如果您可以避免在不需要的地方添加相分离依赖。

像这样的决定对于现代编译器来说非常、非常 - 即使是非常简单的 TCC will perform some amount of dead-code elimination; powerful systems like LLVM 和 GCC 也会发现这一点,而且要复杂得多作为人类,您 reader 可能会错过的案例(通过跟踪变量的生命周期和修改,而不是简单地查看单个点)。

这是对完全编译的其他优点的补充,例如 if 中的代码将被检查是否有错误(而 #if 对于删除 在您当前的系统上会错误,例如引用不存在的平台功能)。

不是直接的答案,但可能会有帮助。有特定于编译器的内部函数来执行代码删除。

对于 MSVC,它是 __assume(0)

对于GCC/Clang,是__builtin_unreachable()

但是请注意,如果您这样写:

if (cond){
  __builtin_unreachable();
  doSomething()
}

您的条件永远不应计算为 true,否则行为未定义。 结合 && REMOVE_UNUSED_CODE__builtin_unreachable() 确保您的代码将被编译器删除。