10

C で次のコードを検討してください。

void main()
{
    int a=0;

    for(printf("\nA"); a; printf("\nB"));

    printf("\nC");
    printf("\nD");     
}

Turb C++ バージョン 3.0 と gcc-4.3.4 を使用してコンパイルすると、両方のケースで出力として次のようになります。

A
C
D

ただし、次のコードをコンパイルすると:

void main()
{
    for(printf("\nA"); 0; printf("\nB"));

    printf("\nC");
    printf("\nD");
}

gcc-4.3.4 による出力は前のケースと同じですが、turbo c++ 3.0 は次の出力を生成します。

A
B
C
D

まず、ここで何が起こっているのかわかりません!さらに、gcc コンパイラによる出力は両方のコードで同じですが、turboc++ 3.0 コンパイラの場合、出力が異なるのはなぜですか? 誰かが光を当てることができますか?

編集 :

実際、あるIT企業の面接でこの質問をされた人がいて、答えられなかったとき、面接官はこのように説明しました。しかし、これはばかげていると思います。言語によって提供される「機能」であるかのように、「バグ」を使用するように誰かに依頼するにはどうすればよいでしょうか? それを「設備」「技法」と呼ぶには、二番目の式にリテラルとして 0 を渡しても、値が 0 の変数を渡しても結果は同じだったはずです。

インタビュアーがそのような質問をするのは非常に愚かであり、それは彼の無能さを示していると結論付けるのは間違っていますか?

4

5 に答える 5

12

2 番目の例の TCC 出力は間違っています。

C99 標準から:

ステートメント

for ( 節 1 ; 式 2 ; 式 3 ) ステートメント

expression-2は、ループ本体の各実行前に評価される制御式です。式expression-3は、ループ本体の各実行後に void 式として評価されます。[...]

明らかに、ここには反復がないため、expression-3は決して実行されません。

同様に、C90 標準 (または少なくとも私が見つけたドラフト) では、次のように述べています。

ループ本体の continue ステートメントの動作を除いて、ステートメントは

     for (  expression-1 ;  expression-2 ;  expression-3 )  statement

および一連のステートメント

      expression-1 ;
     while ( expression-2) {
               statement
              expression-3 ;
     }

同等です。

于 2012-06-18T16:15:46.573 に答える
3

Turbo C++ 3.0 は 1990 年代にリリースされ、すぐに 3.1 がリリースされました。

あなたの古いコンパイラには多くのバグがあり、それらはすぐに更新されたと思います。さらに、そのようなバグはなかったかもしれませんが、新しいパイプ ライニング アーキテクチャでは失敗する最適化されたアセンブリを出力した可能性があります。

いずれにしても、Turbo C++ 3.0 が現在のプラットフォームでサポートされていないことが保証されています。プラットフォームが 20 年近く後に作成されたためにコンパイラがサポートされていないということになると、間違ったプログラムを発行したことでコンパイラを責めることはできません。

于 2012-06-18T16:19:45.200 に答える
2

gcc の出力は正しいです。

最初のケースの Turbo C++ 3.0 出力は正しいです。

2 番目のケースの TurboC++ 3.0 の出力は間違っています。

Turbo C++ 3.0 コンパイラで、不適切なコード生成につながるエッジ ケースを発見したようです。

C または C++ の for-stmt には、一般的な構文があります。

for (初期化; テスト; 再初期化) stmt

初期化は、ループが開始する前に 1 回実行されます。テストはループの TOP で実行されます。テストが真の場合、stmt が実行され、次に再初期化が実行され、ループが繰り返されます。

あなたの場合、printf("\nA") は初期化、a (または 0) はテスト、printf("\nB") は再初期化、stmt は空です。

あなたはAを見たはずです(そしてあなたは見ました)。テストは最初のパスで失敗するはずです。つまり、stmt は表示されないはずであり (しかしわかりません)、B も表示されないはずです。これは、Turbo C++ 3.0 が 2 番目のテストで失敗した場所です。

于 2012-06-18T16:20:48.513 に答える
1

Cの完全な「for」ループ構文は何ですか(互換性がある場合は他の構文も)?

この質問は、規格の該当する部分を引用しています。3 番目の式は、ループが少なくとも 1 回実行されない限り評価されるべきではありません。したがって、2 番目のケースでは、古いコンパイラが「B」を出力するのは間違っていると言えます。

于 2012-06-18T16:16:27.220 に答える
1

のセマンティクスforは、最初の式が評価され (イニシャライザ)、次に 2 番目の式が評価され (ターミネータ)、次にターミネータが非ゼロと評価された場合、for の本体が実行され、3 番目の式 (進行) が評価されて戻るというものです。ターミネーターの評価に。

体がないので、その部分は式が評価されないことになります。これに基づいて、ループは次のように実行する必要があります。

printf("\nA");
a; // yields 0 -> terminate loop

これは実際に起こることです。

2 番目の例では、0 が 0 に評価されるため、( gccの場合と同様に) 同じことが発生するはずです。

ターボ C++ -- 0 定数を見て -- ある種のループ展開の最適化を実行しようとした (そしてそれを適切に実行できなかった) 可能性があります。

于 2012-06-18T16:20:16.433 に答える