2011-01-10 14 views
15

次のコードの出力が正しいのはなぜですか? int GGTにreturn文はありませんが、コードはとにかく動作しますか?グローバル変数は設定されていません。戻り値なしの値を返す関数

#include <stdio.h> 
#include <stdlib.h> 

int GGT(int, int); 

void main() { 
    int x1, x2; 
    printf("Bitte geben Sie zwei Zahlen ein: \n"); 
    scanf("%d", &x1); 
    scanf("%d", &x2); 
    printf("GGT ist: %d\n", GGT(x1, x2)); 
    system("Pause"); 
} 

int GGT(int x1, int x2) { 
    while(x1 != x2) { 
     if(x1 > x2) { 
      /*return*/ x1 = x1 - x2; 
     } 
     else { 
      /*return*/ x2 = x2 - x1; 
     } 
    } 
} 
+6

コンパイル時に警告レベルを上げると、メッセージが表示されるはずです。 –

+0

警告メッセージが表示されますが、なぜ機能するのかはわかりますが、コンパイラは戻り値を設定しますか誰もいない? –

+1

[C関数はintとして定義されていますが、本体にはreturn文がありませんが、まだコンパイルされています](http://stackoverflow.com/questions/4260048/c-function-defined-as-int-but-having-no-体中静止ステートメントを返す) –

答えて

27

少なくともx86の場合、この関数の戻り値はeaxレジスタにある必要があります。そこにあったものは、呼び出し元の戻り値とみなされます。

eaxはリターンレジスタとして使用されるため、保存する必要がないため、caleeによって「スクラッチ」レジスタとして使用されることがよくあります。これは、ローカル変数のいずれかとして使用される可能性が非常に高いことを意味します。両方とも最終的には等しいので、正しい値がeaxに残る可能性が高くなります。

+0

どこがeaxレジスターですか? Cpuは登録しますか? – Anjaneyulu

11

あなたのコンピュータで動作していても、動作しなくても、すべてのコンパイラとターゲットOSで動作しません。

おそらく、intを返す関数は常に何かを返す関数で、通常はレジスタの内容です。戻り値に使用されるレジスタは、関数から返る前に最後の式を計算するために同じものが使用されます(x86ターゲットでは確かにeaxです)。

これは、リターンがないことを検出する最適化コンパイラは、この関数のコードを完全に削除することができます。これ以降、より高い最適化レベルをアクティブにすると、あなたが見える効果が消えることがあります。

私はgccでそれをテスト:最適化せず

GCC: 入力10、20 - >結果は10の

GCC -O1 入力10、20 - >結果は、1つの

GCCであります-O2 入力10,20 - >結果は0

+1

彼は何を信じているのか嫌いであるのか説明していますか? – kriss

-3

ポインタを使用している場合はreturn文は必要ありません。通常、Returnステートメントでは1つの値しか返すことができませんが、ポインタを使用する場合は、必要な数を返すことができます。

scanf( "%d"、& x1); X1の値ではなく、X1のアドレスを機能させます。ポインタは幅のアドレスを扱います。あなたは、本を読んで、ポインタの働き方を学ぶことができます。

+0

私はポインタを使って作業すると、変数のスコープも設定されているとは思わない –

+1

しかしこれは質問とは関係ありません。 –

+0

OH、申し訳ありませんが、申し訳ありません。私はそこに書いたと思った。 GGT(&x1、&x2))とint GGT(int * x1、int * x2)です。私はコードを慎重に読んではいけません、私は正直ではありません、ごめんなさい。 :) – VakhoQ

3

x86では、戻り値はEAXレジスタに格納されます。この値は、算術演算の結果(または少なくとも減算)を格納するためにこのコンパイラで「偶然」使用されます。これはコンパイラによって生成されたアセンブリを調べることで確認できます。私はkrissに同意します - あなたはこれが常にそうであると仮定することはできませんので、明示的に戻り値を指定する方が良いです。

+0

これはいつもうまくいくとは思わないが、私は興味があった。ご回答有難うございます! –

0

このような場合、GCCは「ret」命令をペーストしますが、実行時にclangペースト "ud2"とアプリケーションがクラッシュします。