if-else块中的“ if(0)”块的用途是什么?

时间:2018-11-14 11:00:18

标签: 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
}

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

我曾尝试在SO和互联网上搜索这种明显的情况,但没有成功。关于JavaScript,也有类似的问题,但没有关于C的问题。还有另一个问题,What happens when a zero is assigned in an `if` condition?,但它讨论了变量的零赋值,而不是'if(0)'用法本身。

16 个答案:

答案 0 :(得分:104)

如果有#if条语句,这会很有用

   if (0)
   {
       // Empty block
   }
#if TEST1_ENABLED
   else if (test1())
   {
      action1();
   }
#endif
#if TEST2_ENABLED
   else if (test2())
   {
      action2();
   }
#endif

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

答案 1 :(得分:89)

我有时将其用于对称性,因此我可以与其他编辑者自由移动else if{,而不必介意第一个if

语义上

if (0) {
    // Empty braces
} else 

part不会执行任何操作,您可以依靠优化程序将其删除。

答案 2 :(得分:44)

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

where 1 = 1

这大概使添加其他条件变得更加容易,因为所有其他条件都可以用and开头,而不是进行其他检查以查看它是否是第一个条件。

答案 3 :(得分:42)

按照书面规定,if (0) {}子句编译为空。

我怀疑此阶梯顶部的子句的功能是提供一个方便的位置,通过将0更改为{{,以暂时禁用所有其他功能(出于调试或比较目的)) 1}}或1

答案 4 :(得分:15)

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

之所以发生这种情况,是因为进行了一些代码修改,其中删除了一个主要条件(例如,在初始if块中的函数调用),但是开发人员/维护人员

因此,他们没有删除关联的if块,而是只是将条件更改为if(0)并继续前进。

答案 5 :(得分:15)

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

调试通常是在未优化的代码上进行的,因此将始终存在错误测试,并能够在其上设置断点。当编译用于生产时,代码行将被优化。看似无用的产品线为开发和测试版本提供了功能,而不会影响发行版本。

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

答案 6 :(得分:14)

代码腐烂。

在某些时候,“如果”做了一些有用的事情,情况就发生了变化,也许正在评估的变量被删除了。

正在修理/更改系统的人做了尽可能少的事情来影响系统的逻辑,因此他只是确保代码可以重新编译。所以他留下了一个“ if(0)”,因为这很容易,而且他也不完全确定那是他想要做的。他使系统正常工作,并且没有回去完全修复它。

然后下一个开发人员出现并认为这是故意完成的,并且只注释掉了该部分代码(因为无论如何都没有对其进行评估),然后下次修改该代码时,这些注释被删除。

答案 7 :(得分:9)

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

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

Session

曾经被预编译过的

if ( ${requestIsNotHttps} ){ ... }else if( ...

希望这可以帮助您恢复亲回收编码器时代潜在的低键盘活动,对此我表现出热情!

答案 8 :(得分: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

答案 9 :(得分:6)

我认为这只是错误的代码。在Compiler Explorer中写一个简单的例子,我们看到在gcc和clang中,即使完全禁用了优化,也不会为if (0)块生成代码:

https://godbolt.org/z/PETIks

尝试删除if (0)不会更改生成的代码,因此我得出结论,这不是一种优化。

顶部if块中可能有某些内容后来被删除了。简而言之,似乎删除它会导致生成完全相同的代码,所以请随意这样做。

答案 10 :(得分:6)

如前所述,零的计算结果为false,分支可能会被编译器优化。

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

if (feature_a_active()) {
    use_feature_a();
} else if (some_fn()) {
   ...

成为

if (0) {
   // empty
} else if (some_fn()) {
   ...

答案 11 :(得分:1)

仅在将块1放入时,这有助于调试该块。这将禁用所有if else块功能。而且我们还可以扩展if else块。

答案 12 :(得分:1)

@PSkocik的回答很好,但是我加了两美分。不确定我应该作为评论还是作为答案;选择后者,是因为恕我直言值得其他人看到,而评论则经常不可见。

我不仅偶尔使用

if(0) {
   //deliberately left empty
} else if( cond1 ) {
   //deliberately left empty
} else if( cond2 ) {
   //deliberately left empty
...
} else {
   // no conditions matched
}

但我偶尔也会这样做

if( 1 
    && cond1 
    && cond2
    ...
    && condN
) {

if( 0 
    || cond1 
    || cond2
    ...
    || condN
) {

用于复杂条件。出于相同的原因-易于编辑,#ifdef等

为此,我将在Perl中进行

@array = (  
    elem1,
    elem2,
    ...
    elem1,
) {
  • 请注意列表末尾的逗号。我忘记了逗号在C和C ++列表中是分隔符还是分隔符。恕我直言,这是我们了解到的一件事:[Are trailing commas in Perl a bad practice?逗号]是一件好事。像任何新的符号一样,它需要一段时间才能习惯。

我将if(0)代码与lisp进行比较

(cond   (test1    action1)
   (test2    action2)
   ...
   (testn   actionn))

您猜对了,我可能缩进为

(cond   
   (test1    action1)
   (test2    action2)
   ...
   (testn   actionn)
)

我有时试图想像一下这种可能更具人类可读性的语法。

也许

IF
:: cond1 THEN code1
:: cond2 THEN code2
...
:: condN THEN codeN
FI

受到Dikstra的[https://en.wikipedia.org/wiki/Guarded_Command_Language#Selection:_if][Guarded命令语言]的启发。

但是这种语法意味着条件是并行评估的,而if...else-if意味着条件的顺序评估和优先评估。

在编写会生成其他程序的程序时,我开始做这种事情,这特别方便。

尽管如此,当使用英特尔旧的iHDL编写RTL时,我已经编写了类似的代码

   IF 0 THEN /*nothing*/
   **FORC i FROM 1 TO 10 DOC** 
   ELSE IF signal%i% THEN    
      // stuff to do if signal%i% is active
   **ENDC** 
   ELSE   
      // nothing matched 
   ENDIF

其中FORC..DOC..ENDC是宏预处理器循环结构,它扩展为

   IF 0 THEN /*nothing*/
   ELSE IF signal1 THEN    
      // stuff to do if signal1 is active
   ELSE IF signal2 THEN    
      // stuff to do if signal2 is active
   ...
   ELSE IF signal100 THEN    
      // stuff to do if signal100 is active
   ELSE   
      // nothing matched 
   ENDIF

这是单次分配的非强制性代码,因此,如果您需要执行诸如查找第一个设置位之类的操作,则不允许设置状态变量。

   IF 0 THEN /*nothing*/
   ELSE IF signal1 THEN    
      found := 1
   ELSE IF signal2 THEN    
      found := 2
   ...
   ELSE IF signal100 THEN    
      found := 100
   ELSE   
      // nothing matched 
   ENDIF

想一想,这可能是我第一次遇到这样的结构。

顺便说一句,有些人对if(0)风格有异议-else-if条件是顺序依赖的,不能随意重新排序-不适用于RTL中的AND和OR和XOR逻辑-但确实适用短路&&和||。

答案 13 :(得分:1)

    Actually according to my opinion, if we put any variable for checking inside
    e.g:-
public static void main(string args[])
{
        var status;
        var empList=_unitofWork.EmpRepository.Get(con=>con.isRetired==true);
        //some code logic 
        if(empList.count>0)
        {
          status=true;
        }
        if(status)
        {
         //do something
        }
        else
        {
        //do something else
        }
}
     if then its dynamically get the value in run time and invoke the logic inside it, else its simply extra line of code i guess.

    Anybody have any depth knowledge why this thing is used....or agree with me.
    kindly respond. 

答案 14 :(得分:-1)

例如,我已经看到它用于处理错误

if(0){
lable1:
   //do something
}
if(0){
lable2:
   //do something
}
.
.
and so on.

if(condition_fails)
   goto lable1;

这在使用goto来管理错误时非常有用,仅在发生错误时才执行语句。我在非常古老的C代码中看到了这一点(函数参数写在'()'之外),不要以为现在有人遵循了。

答案 15 :(得分:-2)

我已经看过几次了,我认为最可能的原因是它正在评估旧版本/不同版本的代码/分支中的某些内容,或者可能是为了进行调试,然后将其更改为if(0)删除其中所有内容的方法有些懒惰。