16

C に似た言語では、次のような if ステートメントを使用することに慣れています。

if(x == 5) {
    //do something
}
else if(x == 7) {
    //do something else
}
else if(x == 9) {
    //do something else
} else {
    //do something else
}

私の質問は、コンパイラは if ステートメントをそのように認識しますか、それとも最終的に次のように解釈されますか?

if(x == 5) {
    //do something
}
else {
    if(x == 7) {
        //do something
    }
    else {
        if(x == 9) {
            //do something
        }
        else {
            //do something else
        }
    }
}

編集: 質問は私の頭の中では理にかなっていますが、一般大衆にはおそらくかなりばかげているように聞こえることに気付きました. 私は、ASTがどのように見えるか、そして「else-if」ステートメントに特別なASTケースがあるかどうか、またはカスケードif/elseブロックとしてコンパイルされるかどうかについてもっと言及していました.

4

5 に答える 5

17

それらは C コンパイラと同等です。else ifC には特別な構文はありません。2 番目ifは単なる別のifステートメントです。


明確にするために、C99 標準によれば、if ステートメントは次のように定義されます。

selection-statement:
    if (expression) statement
    if (expression) statement else statement
    switch (expression) statement

複合文は次のように定義されます。

compound-statement:
    {block-item-list(opt) }
block-item-list:
    block-item
    block-item-list block-item
block-item:
    declaration
    statement

コンパイラのフロントエンドがソース コード ファイルを理解しようとするとき、多くの場合、次の手順に従います。

  1. 字句解析: 平文のソース コードを「トークン」のリストに変換します。
  2. セマンティック分析: トークン リストを解析し、抽象構文ツリー (AST) を生成します。

次に、ツリーはコンパイラのミドルエンド (最適化するため) またはバックエンド (マシンコードを生成するため) に渡されます。

あなたの場合、このifステートメント

if(x == 7) {
    //do something else
} else if(x == 9) {
    //do something else
} else {
    //do something else
}

選択ステートメント内の選択ステートメントとして解析されます。

    selection-stmt
    /     |      \
 exp     stmt     stmt
  |       |        |
 ...     ...    selection-stmt
                /      |      \
              exp     stmt    stmt
               |       |       |
              ...     ...     ...

そしてこれ

if(x == 7) {
    //do something else
} else {
    if(x == 9) {
        //do something else
    } else {
        //do something else
    }
}

選択ステートメント内の複合ステートメント内の同じ選択ステートメントです。

    selection-stmt
    /     |      \
 exp     stmt     stmt
  |       |        |
 ...     ...    compound-stmt
                      |
                block-item-list
                      |
                  block-item
                      |
                     stmt
                      |
                selection-stmt
                /      |      \
               exp    stmt    stmt
                |      |       |
               ...    ...     ...

したがって、それらは異なるASTを持っています。しかし、コンパイラのバックエンドには違いはありません。AST でわかるように、構造的な変更はありません。

于 2013-06-09T03:07:41.723 に答える
12

C と C++ の両方で、ステートメントを冗長な のペアに囲ん{}でも、プログラムのセマンティクスは変わりません。この文

a = b;

これと同等です

{ a = b; }

これと同等です

{{ a = b; }}

そしてこれに

{{{{{ a = b; }}}}}

冗長性{}はコンパイラにまったく違いをもたらしません。

あなたの例では、最初のバージョンと 2 番目のバージョンの唯一の違いは、上記の例{}で行ったように、後者に追加した冗長性の束ですa = b。あなたの余分な{}変更は絶対に何もありません。あなたが提示した 2 つのバージョンのコードに大きな違いはないため、質問は本質的に意味がありません。

質問を明確にするか、他のことについて質問するつもりなら、コードを修正してください。

于 2013-06-09T04:12:23.790 に答える
1

実際、2 つのコード スニペットは同一です。「if」ステートメントの構文が次のようになっていることを理解すると、これが真である理由がわかります。

if <expression>
    <block>
else
    <block>

NOTE that <block> may be surrounded by curly braces if necessary.

したがって、コードは次のように分解されます。

// if <expression>
if (x == 5)

// <block> begin
{
    //do something
}
// <block> end

// else
else

// <block> begin
if(x == 7) {
    //do something else
}
else if(x == 9) {
    //do something else
} else {
    //do something else
}
// <block> end

言語で許可されているように、「else」のブロックを中括弧で囲むと、2 番目の形式になります。

// if <expression>
if (x == 5)

// <block> begin
{
    //do something
}
// <block> end

// else
else

// <block> begin
{
    if(x == 7) {
        //do something else
    }
    else if(x == 9) {
        //do something else
    } else {
        //do something else
    }
}
// <block> end

そして、これをすべての「if else」句に対して繰り返し行うと、正確に 2 番目の形式になります。2 つのコードはまったく同じであり、コンパイラからはまったく同じように見えます。

于 2013-06-09T03:21:33.620 に答える
0

最初のステートメントはif-elseの「はしご」規則に従ってインデントされていますが、実際には、真のネストを明らかにする「正しい」インデントは次のとおりです。

if(x == 5) {
    //do something
} else 
  if(x == 7) {              // <- this is all one big statement
    //do something else
  } else 
    if(x == 9) {            // <- so is this
      //do something else
    } else {
      //do something else
    }

インデントは空白です。コンパイラにとっては何の意味もありません。最初の後にあるのelseは、1 つの大きなif声明です。これは 1 つのステートメントにすぎないため、中かっこで囲む必要はありません。「コンパイラはそのように読み取るか」と尋ねると、ほとんどのスペースは重要ではないことを覚えておく必要があります。構文は、構文ツリーの真のネストを決定します。

于 2013-06-09T04:57:29.720 に答える