2016-12-28 11 views
1
#include <stdio.h> 

int add(int, int); 

int main(int argc, char const *argv[]) 
{ 
    int a = 2, b = 3; 
    printf("%d %d %d\n", a, b, add(a, b)); 
    return 0; 
} 

int add(int a, int b) { 
    int c = a + b; 
    return; 
} 

上記のプログラムの出力は2 3 5でどのようにすることができ、明示的にそれ関数の戻り値は何

+0

XY問題:なぜあなたはCを返そうとしませんか? –

+0

@ Jean-FrançoisFabre私は、Cが明示的にそれを返すことなく返される方法を知りたがっています。 –

答えて

1

@P.P.の答えは正しい:これは未定義の動作です。

実際には、コンパイラの実装に大きく依存します。 最も可能性の高いシナリオは、呼び出し元関数が戻り値をとることです。呼び出し先関数は値を返さないので、呼び出し元関数はスタックから「ランダム」な値を取ることになります。

私は(任意の最適化なし)GCCコンパイラであなたの例を提供するつもりです:

これは機能addのためのアセンブリコードです:

push %rbp 
mov %rsp,%rbp 
mov %edi,-0x14(%rbp) 
mov %esi,-0x18(%rbp) 
mov -0x14(%rbp),%edx 
mov -0x18(%rbp),%eax 
add %edx,%eax 
mov %eax,-0x4(%rbp) 
nop 
nop 
pop %rbp 
retq 

さらに、あなたが見ることができるように変数がcに格納されます。 結果値は幸いにも%eaxレジスタに格納されますが、これは目的のために行われていません。あなたが見ることができるように

push %rbp 
mov %rsp,%rbp 
mov %edi,-0x14(%rbp) 
mov %esi,-0x18(%rbp) 
mov -0x14(%rbp),%edx 
mov -0x18(%rbp),%eax 
add %edx,%eax 
mov %eax,-0x4(%rbp) 
mov -0x4(%rbp),%eax <==== 
pop %rbp 
retq 

は、cに格納された値が正しく%eaxレジスタに移動させる(<====でマークされた命令で):

ここ正しい機能のアセンブリコードがあります。 main機能(呼び出し側)で

は、代わりに、アセンブリは次のとおりです。

callq 0x400542 <add> 
mov %eax,%ecx 

あなたは、呼び出し元の機能を見ることができるように、関数の呼び出しの後、想定している「戻り値」を取ります%eaxに登録してください。

これは、呼び出し元関数が実際に値を返すにもかかわらず、呼び出し元関数は戻り値をとることを意味します。

私があなたに示した例では、呼び出し元が返す戻り値は%eaxです。結論として

呼び出し先機能が適切な値を返さない場合、呼び出し元機能(メイン)は呼び出し先が適切Aを返さない場合は汚れの値とすることができる%eaxレジスタ(に格納されているものとにかくかかりますが値)。

5

それはundefined behaviourを返さずだadd関数の戻りC。

値を返すことになっています機能はとてもをしない呼び出し側が戻り値を使用している場合、それは未定義です。あなたが観察するかもしれないものは、純粋に偶発的/プラットフォーム固有の行動であり、依拠されるものではありません。 Cの標準は確かに保証をしません。 C11ドラフト、6.9.1 Function definitions/12から

もし}関数を終了達し、 関数呼び出しの値が呼び出し元によって使用され、動作は未定義です。

+3

あなたは、値がおそらくスタックにあり、戻り値として取られていると説明することができますが、それは純粋な運と実装に依存します。 –