はC

2012-06-18 4 views
10

のループコードのためにこれを理解することを助ける必要があるCに次のコードを考えてみましょう:私はTURB C++バージョン3.0とgcc-4.3.4を使用して、それをコンパイルするとはC

void main() 
{ 
    int a=0; 

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

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

、私は、出力として次を得ます両方の場合:ただし

A 
C 
D 

私は、次のコードをコンパイルした場合、:

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

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

はGCC-4.3.4による出力は、前と同じですすべての

A 
B 
C 
D 

まず、私はここで何が起こっているか見当がつかない:viousケースが、ターボC++ 3.0には、次の出力を生成します!さらに、gccコンパイラの出力はどちらのコードでも同じですが、turboC++ 3.0コンパイラの場合、出力は異なりますか?誰かが光を放つことができますか?

EDIT:

は実際に誰かがIT企業のためのインタビューで、この質問をしたと彼は答えを与えるために失敗したときに、インタビュアーがこの説明を与えました。しかし、私はこれが馬鹿だと思っています。どのように "バグ"をその言語によって提供される "施設"のように使うように誰かに頼むことができますか? 「ファシリティ」と「テクニック」と呼ばれるためには、2番目の式のリテラルとして0を渡すか、値が0の変数を渡すかにかかわらず、結果は同じであったはずです。

私は面接官がそのような質問をすることは非常に愚かであり、彼の無能を示していると間違っていると思いますか?

+5

これはコンパイラの興味深い違いですが、なぜ世界で最初にそのような 'for'ループを使用するのですか? – JAB

+0

Cの "for"ループの構文を完全に誤解していますか?プログラミング言語で物事を書く方法を推測するだけでは、書籍やウェブコースなどが必要です。 –

+3

@ ThomasPadron-McCarthy実際、構文はうまくいきます。それはまったく有効ではないようですが、「My cold is a toe」という文章が構文的に完全に有効ですが、ナンセンスなフレーズであるように、完全に有効です。最初の部分 'printf(" \ nA ")'は、ループの開始時に実行されます。ループがfalse/0に評価されたときに実行を停止させるセンチネル表現は、最初のもの(== 0)の場合は「a」で、2番目の場合はリテラルの「0」です。 [cont。] – JAB

答えて

12

第2の例のTCC出力が間違っています。 C99標準から

(;式2発現-3句-1)用

ステートメント

ステートメント

は、次のように動作します。式式-2は、ループ本体の実行ごとに評価される式 です。 式式-3は、ループ本体の実行ごとに の後にvoid式として評価されます。 [...]

はもちろん、ここには反復は存在しないので、表現-3を実行すべきではありません。同様に

、C90規格(または少なくともdraft that I found中)で、それは言う:ループ本体でcontinue文の振る舞いを除き

、 声明

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

およびステートメントのシーケンス

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

は同等です。

+0

私は心に残っています。私は私の答えを取り除きます。 – Jack

+0

明らかにTurbo C++ 3.0はC99より8年先立っています。それはいくつかの奇妙な最適化手法かもしれません。 –

+0

@HristoIliev:更新された回答を参照してください... –

3

Turbo C++ 3.0は1990年代にリリースされ、非常に迅速に3.1のリリースでフォローアップされました。

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

、それはターボC++ 3.0があなたの現在のプラットフォームでをサポートされていないを保証しています。 20年近く後にプラットフォームが作成されたため、コンパイラーがサポートされていない場合は、間違ったプログラムを発行しても実際にはそれを実行できません。

+0

AFAIK、CPUパイプライニングのようなものへの変更は、プログラマにとって透過的でなければなりません。 –

1

セマンティクスforは、最初の式が評価され(初期化子)、次に2番目の式が評価される(ターミネータ)場合、ターミネータが非ゼロと評価された場合、forの本体が実行され、 )が評価され、ターミネータの評価に戻ります。

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

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

これは実際に起こります。 2番目の例では

0は0

ことが可能であると評価されたとして(gccののためであると)同じことがターボC++こと起こるはず - 0定数を見ては、 - いくつかを実行しようとしましたループアンローリング最適化の一種(適切に実行できませんでした)

+0

私はそれが 'i <0'ではなく、単に' 0'であることを認識するまで、ループアンローリングストーリーは妥当であるとほとんど思っていました。 – lvella

2

gcc出力が正しいです。

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

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

Turbo C++ 3.0コンパイラで、コード生成が正しく行われないことがあります。(;テスト、再初期化初期化)初期化がループ開始前に、一度実行さ

STMT

Aは、FOR-STMT CまたはC++での一般的な構文

を有しています。テストはループのTOPで実行されます。テストが真であれば、stmtが実行され、再初期化が実行され、ループが繰り返されます。

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

あなたはAを見たことがあります。テストは最初のパスで失敗したはずです。つまり、あなたはstmtを見たことがないはずですが、あなたはそれを見たことがないはずです。これは、Turbo C++ 3.0が2番目のテストで失敗したところです。