if-else块中'if(0)'块的目的是什么?

Zza*_*nka 140 c if-statement

我的问题是关于我在主题中提到的那条线,我可以在生产代码中的许多地方看到.

整体代码如下所示:

if (0) {
    // Empty braces
} else if (some_fn_call()) {
    // actual code
} else if (some_other_fn_call()) {
    // another actual code
    ...
} else {
    // default case
}
Run Code Online (Sandbox Code Playgroud)

其他分支与我的问题无关.我想知道放在if (0)这里的含义是什么.大括号是空的,所以我认为它不应该评论一些代码块.它会强制编译器进行一些优化还是意图不同?

我试图在SO和互联网上搜索这个明确的案例,但没有成功.关于JavaScript有类似的问题,但不是C.还有另一个问题,当在`if`条件中分配零时会发生什么?,但它讨论了对变量的零赋值,而不是'if(0)'用法本身.

CSM*_*CSM 104

如果有#if语句,则这可能很有用

   if (0)
   {
       // Empty block
   }
#if TEST1_ENABLED
   else if (test1())
   {
      action1();
   }
#endif
#if TEST2_ENABLED
   else if (test2())
   {
      action2();
   }
#endif
Run Code Online (Sandbox Code Playgroud)

等等

在这种情况下,任何(和所有)测试都可以被#if删除,代码将正确编译.几乎所有编译器都会删除该if (0) {}部件.一个简单的自动生成器可以生成这样的代码,因为它稍微容易编码 - 它不必单独考虑第一个启用的块.

  • 在许多情况下,`if` /`else if`链不是用作决策树,而是用作"第一匹配条件下的行为"构造,其中恰好具有最高优先级的条件是特别"特别".虽然我没有看到`if(0)`用作允许所有真实分支具有一致语法的方法,但我喜欢它所促进的一致语法. (5认同)
  • @KonradRudolph,如果你想把警卫的数量增加一倍,并且提到的保护条件数增加三倍,我认为没问题. (5认同)

PSk*_*cik 90

我有时使用它来对称,所以我可以else if{用编辑器自由地移动另一个,而不必考虑第一个if.

语义上的

if (0) {
    // Empty braces
} else 
Run Code Online (Sandbox Code Playgroud)

part没有做任何事情,你可以指望优化器删除它.

  • 个人观点:虽然这可能是为什么它按原样编写的原因,但我认为这是一个不好的理由.代码的读取频率高于编写代码,这种不必要的代码只会增加读取器的解析开销. (237认同)
  • 似乎它肯定会降低可读性.它是如此糟糕,它发送程序员到SO询问它是什么.不是一个好兆头. (77认同)
  • 我不认为`if(0){..}`引入任何可解析性/可读性问题.对于那些了解一点C的人来说,这应该是显而易见的.这不是问题.问题是阅读之后的后续问题:"那到底是什么时候?" 除非它是用于调试/临时目的(即,意图是"启用"以后"if"阻止),我主张*完全删除*.基本上"阅读"这样的代码可能会导致读者不必要的"暂停",没有充分的理由.这是一个很好的理由去除它. (72认同)
  • 即使使用这种模式,我也不知道你是否可以"无需担心地"在编辑器周围"移动",因为条件可能不是相互排斥的,在这种情况下*order*很重要.就个人而言,我只会使用`if`,并执行[提前退货](https://softwareengineering.stackexchange.com/questions/18454/should-i-return-from-a-function-early-or-use-an- if-statement),在必要时将逻辑链提取到单独的函数. (26认同)
  • @ user694733:您可能会争辩说,所有重要代码路径的常用`if else`前缀可以很好地排列条件,并且可以更轻松地扫描它们.(但这是主观的,并且将取决于条件和代码块中的许多内容.) (13认同)
  • @PSkocik,确实,正如 Lundin 在问题本身的评论中提到的那样,这将是防御性编程中的一个很好的习惯用法,它允许您在开头抛出这个“if (0)”,最后抛出默认的“未处理”情况然后在里面加入有意义的树枝。 (2认同)
  • 特别是,如果`else if`条目都是单行,那么领先的`if(0)`可以帮助"_aesthetically_"...例如`else if(conditonA())actionA()的序列;`... `else if(conditonE())actionE();`lines(有或没有大括号,如你所见). (2认同)
  • 有人可能这样做的另一个原因是他们可以在不破坏的情况下评论和取消注释不同的ifelse语句.我在SQL中听到过类似的策略:`where 1 = 1`然后在其他行上使用`和statement`. (2认同)
  • @JohnWu 条件不是相互排斥的,并且依赖于顺序正是使它们易于重新排序的原因。如果订单无关紧要,则无需重新订购。如果是这样,您可能需要这样做。另外,现在的引文说的是*“不必介意第一个if”*,而不是*“不用担心”*。 (2认同)
  • @Mołot它从未说过"不用担心".在C中,必须始终担心:D. (2认同)

Set*_*ers 44

我见过在生成代码中使用的类似模式.例如,在SQL中,我看到库发出以下where子句.

where 1 = 1
Run Code Online (Sandbox Code Playgroud)

这可能会更容易添加其他标准,因为可以添加所有其他标准,and而不是额外检查,看它是否是第一个标准.

  • 这在自动生成SQL查询的库中是可以接受的,这些查询很可能甚至不会被DevOps团队看到.在高级代码中,它不是"可接受的",必须多次写入和读取. (7认同)
  • `1 = 1`也是"有用的",因为你总是可以无条件地在前面添加`where`.否则你必须检查它是否为空,如果是,则避免生成`where`子句. (4认同)
  • 此外,大多数数据库会自动从"WHERE"中"删除"`1 = 1`,因此它对性能没有影响. (2认同)

Rus*_*ove 43

如上所述,该if (0) {}条款汇编为零.

我怀疑这个梯子顶部的子句的功能是提供一个简单的位置来暂时禁用所有其他功能(用于调试或比较目的),通过更改0为a 1true.

  • 搞定了.调试后我看不出任何其他原因. (2认同)

Sou*_*osh 16

我不确定是否有任何优化,但我的两分钱:

这是因为一些代码修改,其中一个主要条件被删除,(初始if块中的函数调用,让我们说),但开发人员/维护者

因此if,他们只是将条件更改为if(0)并继续移动,而不是删除关联的块.

  • 是不是`if(0)`也减少了分支覆盖? (3认同)

小智 15

这是代码腐烂.

在某些时候,"if"做了一些有用的事情,情况发生了变化,也许正在评估的变量被删除了.

修复/更改系统的人尽可能少地影响系统的逻辑,因此他只是确保代码重新编译.所以他留下了"if(0)",因为这很快捷,而且他并不完全确定这是他想要做的.他让系统正常工作,他不会完全修复它.

然后下一个开发人员出现并且认为这是故意完成的,并且只注释掉那部分代码(因为它还没有被评估),然后在下次触摸代码时,这些注释被删除.

  • 对。对于古老的代码,请一次更改一个死代码。我无法指望我对“死”代码进行了刀耕火种的次数,却发现刀耕火种遗漏了一些奇怪的副作用。 (2认同)

stu*_*dog 15

尚未提及的一种可能性:该if (0) {线可能为断点提供方便的位置.

调试通常在非优化代码上完成,因此将出现始终为false的测试,并且能够在其上设置断点.编译生产时,代码行将被优化.看似无用的产品线为开发和测试构建提供了功能,而不会影响发布版本.

上面还有其他好的建议; 真正了解目的的唯一方法是追踪作者并提出要求.您的源代码控制系统可能会有所帮助.(寻找blame类型功能.)


sim*_*ame 9

我已经在使用模板语言生成的预扩展JavaScript中看到了无法访问的代码块.

例如,您正在阅读的代码可能是从服务器粘贴的,该服务器预先评估了当时依赖于仅在服务器端可用的变量的第一个条件.

if ( ${requestIsNotHttps} ){ ... }else if( ...
Run Code Online (Sandbox Code Playgroud)

曾经编译过的:

if ( 0 ){ ... }else if ( ...
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助你重新激活专业回收编码器时代潜在的低键盘活动,我表现出热情!


phi*_*lfr 8

该结构也可以在C中用于实现类型安全的通用编程,依赖于编译器仍然检查无法访问的代码这一事实:

// this is a generic unsafe function, that will call fun(arg) at a later time
void defer(void *fun, void *arg);

// this is a macro that makes it safer, by checking the argument
// matches the function signature
#define DEFER(f, arg) \
   if(0) f(arg); \              // never actually called, but compile-time checked
   else defer(f, (void *)arg);  // do the unsafe call after safety check

void myfunction(int *p);

DEFER(myfunction, 42);     // compile error
int *b;
DEFER(myfunction, b);      // compiles OK
Run Code Online (Sandbox Code Playgroud)


cha*_*ite 6

我认为这只是糟糕的代码.在Compiler Explorer中编写一个快速示例,我们看到在gcc和clang中都没有为if (0)块生成代码,即使完全禁用了优化:

https://godbolt.org/z/PETIks

为解决if (0)生成的代码而去除原因并没有改变,因此我得出结论,这不是优化.

可能以前在顶部if块中存在某些东西,后来被删除了.简而言之,看起来删除它会导致生成完全相同的代码,因此请随意执行此操作.


ser*_*opm 6

如上所述,零被评估为假,并且分支可能会被编译器优化掉.

我之前在代码中也看到了这个,其中添加了一个新功能并且需要一个kill-switch(如果该功能出现问题就可以将其关闭),并且一段时间后,当kill-switch被删除时程序员也没有删除分支,例如

if (feature_a_active()) {
    use_feature_a();
} else if (some_fn()) {
   ...
Run Code Online (Sandbox Code Playgroud)

成为

if (0) {
   // empty
} else if (some_fn()) {
   ...
Run Code Online (Sandbox Code Playgroud)