if-elseブロックの「if(0)」ブロックの目的は何ですか?


141

私の質問は、件名で言及した行についてであり、製品コード内の多くの場所で見ることができます。

全体的なコードは次のようになります。

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にはありません。別の質問があります。`if`条件でゼロが割り当てられるとどうなりますか?、しかしそれは変数へのゼロ代入について議論しており、 'if(0)'の使用法自体については触れていません。


2
そのステートメントは無関係であると思われます。そのステートメントの有無にかかわらずアセンブリコードを生成すると、内部で何が行われているのかがわかります。
2018年

2
これは自動生成されたコードである可能性があります。
2018年

回答:


91

私は時々これを対称性のために使用するのでelse if{、最初のものを気にすることなく、エディターで他を自由に動かすことができifます。

意味的に

if (0) {
    // Empty braces
} else 

一部は何もせず、オプティマイザーを使用して削除できます。


239
個人的な意見:これは、このように書かれている理由コードである可能性がありますが、それは正当な理由ではないと思います。コードは書かれたよりも頻繁に読み取られます。この不要なコードは、リーダーの解析オーバーヘッドを増やすだけです。
user694733

13
@ user694733:if elseすべての重要なコードパスの共通のプレフィックスは条件を適切に整列させ、スキャンを容易にすることを主張できます。(ただし、これは主観的なものであり、実際に条件とコードブロックの内部にあるものの多くに依存します。)
M Oehm

72
if (0) {..}解析可能性や読みやすさの問題は発生しないと思います。Cを少しでも知っている人には明らかでしょう。それは問題ではありません。問題は、それを読んだ後のフォローアップの質問です。デバッグや一時的な目的でない限り(つまり、if後でそのブロックを「有効にする」ことが意図されている場合)、完全に削除することをお勧めします。基本的に、そのようなコードを「読み取る」ことは、正当な理由なく、リーダーに不必要な「一時停止」を引き起こす可能性があります。そして、それはそれを削除する十分な理由です。
PP

77
それは間違いなく読みやすさを損なうようです。それはとても悪かったので、プログラマーをSOに送って、それが何のためにあるのか尋ねました。良い兆候ではありません。
Vectorjohn 2018年

26
このパターンを使用してもelse if、条件が相互に排他的ではない場合があり、その場合は順序が重要になるため、「エディターを気にせずに移動」できるかどうかはわかりません。個人的には、を使用し、必要に応じてロジックチェーンを別の関数に抽出し、早期復帰ifを行います。
John Wu

105

これは、#ifステートメントがある場合に役立ちます。

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

この場合、任意の(およびすべての)テストを実行でき#if、コードは正しくコンパイルされます。ほとんどすべてのコンパイラーがそのif (0) {}部分を削除します。単純な自動生成プログラムは、コーディングが少し簡単なので、このようなコードを生成できます。最初の有効なブロックを個別に考慮する必要はありません。


5
多くの場合、if/ else ifチェーンはディシジョンツリーとしてではなく、「最初に一致する条件に基づいて動作する」コンストラクトとして使用されます。この場合、優先度が最も高い条件は特に「特別」ではありません。if(0)実際のすべてのブランチが一貫した構文を持つことを可能にする方法として使用されたとは思っていませんが、それが容易にする一貫した構文が好きです。
スーパーキャット2018年

1
この場合でも、同じ効果を得ることができるため、役に立ちません。else if行を2つに分割して、その間にプリプロセッサガードを挿入するだけです。
Konrad Rudolph

1
@KonradRudolph私はフォローしていません。どのように書きますか?
JiK、

1
@JiKブランチを削除しif (0)、残りをelseの行に沿ってガードで囲まれた独自の行に再フォーマットし#if TEST1_ENABLED && TEST2_ENABLEDます。
Konrad Rudolph

5
@KonradRudolphガードの数を2倍にしたり、言及したガード条件の数を3倍にしたりする場合は問題ないと思います。
ホブ、

44

生成されたコードで使用される同様のパターンを見たことがあります。たとえば、SQLでは、ライブラリが次のwhere句を出力するのを見てきました。

where 1 = 1

これにより、他の基準を追加するのが簡単になると考えandられます。これは、最初の基準であるかどうかを確認する追加のチェックの代わりに、すべての追加の基準を付加できるためです。


4
1=1あなたが常に追加することができますので、また、「有用」であるwhere無条件に、前に。それ以外の場合は、空かどうかを確認する必要があります。空の場合は、where句の生成を避けます。
Bakuriu

2
また、ほとんどのデータベースは、自動的に「削除」をします1=1からWHERE、それがパフォーマンスに影響を与えないように、。
モニカの訴訟に資金を

7
これは、DevOpsチームでも見られない可能性が最も高いSQLクエリを自動的に生成するライブラリでは許容されます。高レベルのコードでは何度も読み書きする必要があるため、これは「許容できません」。
phagio 2018年

これは、最終的な条件の数が不明である種類の動的SQLを生成する場合に非常に便利なアプローチです。
スキッパー2018年

1
@奇妙なことに、私は実際に反対のことを書きました。読みにくい構文は生成されたコードでは受け入れられます。これは、開発者が保守する高レベルの関数コードでは読み取れないためです。
phagio 2018年

44

書かれているように、このif (0) {}句は何もコンパイルされません。

私はこのはしごの上部にある句の機能を変更することにより、(デバッグや比較のために)一度に一時的に無効に他のすべての機能に簡単に場所を提供することである疑い01true


2
ばっちり成功。デバッグ以外の理由は見当たりませんでした。
tfont 2018年

16

私は最適化について確信が持てませんが、私の2セント:

これは、1つの主要な条件(ifたとえば、最初のブロックの関数呼び出し)が削除されたコードの変更が原因で発生しましたが、開発者/メンテナ

したがって、関連するifブロックを削除するのではなく、単に条件をに変更して次にif(0)進みました。


3
if(0)ブランチカバレッジも減らしませんか?
David Szalai

1
@DavidSzalai完全ではない-せいぜい1減少する(前の2から)-しかし、私の知る限りでは、1ヒットがカバレッジに必要です。
Sourav Ghosh

15

コードの腐敗です。

「もし」何か有用なことをしたある時点で、状況が変化し、おそらく評価されている変数が削除されました。

システムを修正または変更していた人は、システムのロジックに影響を与えることはできるだけ少なく、コードが再コンパイルされることを確認しました。それで彼は「if(0)」を残します。なぜならそれは速くて簡単であり、彼はそれが彼がやりたいことだと完全に確信していないからです。彼はシステムを機能させ、完全に修正するために戻ることはありません。

次に、次の開発者がやって来て、それが故意に行われたと考え、コードのその部分だけをコメントアウトします(とにかく評価されていないため)、次にコードに触れたときに、それらのコメントは削除されます。


2
うん。古いコードの場合、一度に1つのデッドコードを削除する変更を加えます。スラッシュアンドバーンで見逃された奇妙な副作用があったことを発見するためだけに、「デッド」コードに対してスラッシュアンドバーンの大暴れを犯した回数を数えることはできません。
オースティンのジュリー

15

まだ言及されていない可能性の1つ: if (0) {ラインがブレークポイントに便利な場所を提供しているがあることです。

デバッグは多くの場合、最適化されていないコードで行われるため、常に偽のテストが存在し、ブレークポイントを設定できます。本番用にコンパイルすると、コード行が最適化されます。一見役に立たないラインは、リリースビルドに影響を与えることなく、開発およびテストビルドの機能を提供します。

上記の他にも良い提案があります。目的が何であるかを本当に知る唯一の方法は、作者を追跡して尋ねることです。あなたのソースコード管理システムがそれを助けるかもしれません。(blame-type機能を探してください。)


9

テンプレート言語を使用して生成された、事前に拡張されたJavaScriptの到達不可能なコードブロックを見ました。

たとえば、読み取っているコードが、サーバー側でのみ利用可能な変数に依存していた最初の条件を事前評価したサーバーから貼り付けられている可能性があります。

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

これはかつてコンパイルされた後であります:

if ( 0 ){ ... }else if ( ...

これが、私が熱意を表明しているリサイクル前のコーダー時代の潜在的なキーボード操作の低さを相対化するのに役立つことを願っています!


1
ユビキタスオートメーションの時代には、自動生成されたコードにもっと頼る必要があります。これにより、実際の作業により多くの時間を費やすことができます。しかし今のところ、私の正確な関心点は、これらすべてが内部でどのように構築されているかです。
Zzaponka 2018年

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

6

それは単に悪いコードだと思います。コンパイラエクスプローラーで簡単な例を書くと、if (0)最適化が完全に無効になっていても、gccとclangの両方でブロックのコードが生成されないことがわかります。

https://godbolt.org/z/PETIks

if (0)原因を削除して遊んでも、生成されたコードは変更されないので、これは最適化ではないと結論付けます。

上のifブロックに何かがあり、後で削除された可能性があります。つまり、これを削除するとまったく同じコードが生成されるように見えるので、自由に実行してください。


6

言われているように、ゼロはfalseと評価され、ブランチはコンパイラによって最適化される可能性があります。

私は以前にも、コードで新しい機能が追加され、キルスイッチが必要であることがわかりました(機能に問題が発生した場合は、単にオフにすることができます)。プログラマはブランチも削除しませんでした、例えば

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

なりました

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

1

ifブロック1を置くだけで、このブロックをデバッグするのに役立ちます。これにより、if elseブロック機能がすべて無効になります。また、if elseブロックを拡張することもできます。


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. 

1

@PSkocikの答えは結構ですが、私は私の2セントを追加します。これをコメントとして行うべきか、それとも回答として行うべきかは不明です。後者を選択するのは、IMHOが他の人に見てみる価値があるのに対し、コメントはしばしば見えないからです。

時々使うだけでなく

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 ++リストでコンマが区切り文字または区切り文字であるかどうか忘れてしまいました。これは私たちが学んだ1つのことです:[ Perlでコンマを末尾に付けることは悪い習慣ですか?コンマ]は良いことです。新しい表記法と同様に、慣れるまでしばらく時間がかかります。

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 Command Language]に。

しかし、この構文は条件が並行して評価されることを意味しますが、 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-conditionsは順次依存しており、任意に並べ替えることはできない-RTLのANDおよびORおよびXORロジックには適用されませんが、short-には適用されます回路&&および||。


-1

私はこれがエラーを処理するために使用されるのを見ました、例えば

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

if(condition_fails)
   goto lable1;

これは、gotoを使用してエラーを管理する場合に役立ちます。エラーが発生した場合にのみステートメントが実行されます。私はこれを非常に古いCコード(関数の引数が '()'の外側に記述されている)で見ましたが、今は誰もこれに従っていないと思います。


-2

私はこれを数回見ましたが、最も可能性の高い理由は、コードの古い/異なるバージョン/ブランチで何かを評価すること、またはおそらくデバッグのためであり、それを変更することif(0)は、そこにあったものを削除するやや面倒な方法です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.