C言語でのreturn
は他動詞ではなく自動詞
2種類の"return"
C言語において、関数は戻り値を返したり返さなかったりする。
ここで、(1)のようなreturn
を「値を返す」ものだと思い込んでしまっていると、(2)のreturn;
の意味がわからなくなることがあるらしい。
この記事では、C言語におけるreturnが「返す」ものでなく「帰る(返る)」ものと捉える方が自然であることを、コンパイル結果を見ながら示していく。
アセンブリレベルで見る
ひとまず上記のtest.cをコンパイルした結果をアセンブリ言語で見てみよう。
環境は 64 bit Linux, gcc-5.4.0 である。
これらのうち、コンパイラが自動生成した箇所を除いてC言語っぽく書き直してみると、以下のようになる。
値を返す場合も何もせず返る場合も、全く同じret
命令が呼ばれているのである。
ret
命令は、だいたい「関数の呼び出し元のアドレスにジャンプする」のような動作を行う、言ってみればgotoのようなものである。
では、add3()
では第1引数に3を足した値を返すが、これはどうやって呼び出し元に伝えられているのか。
実は、戻り値は呼び出された関数が特定のレジスタ(CPU内の記憶領域)、ここではEAX
に格納し、呼び出し元がそのレジスタを参照することで値を得る、という決まりになっているのである。
すなわちreturn
には本来、単に「関数の呼び出し元アドレスへ戻る」という自動詞的な意味しかなく、値を返すというのは「約束の場所に値を置いておく」という利便性のための追加機能である、と考えると自然である。
おまけ: 誰が(何が)返るのか
return
が「関数の呼び出し元アドレスへ戻る」という意味なのは良いとして、その主語は何なのか。
これは「処理」であると考えられる。
「処理が進む」とか「処理が止まる」とか、そういう文脈での「処理」であって、プログラムやアルゴリズム自体を指しての「処理」ではない。
もっと言えば、ここでの「処理」とは実際には「実行中の命令が格納されているメモリアドレス上にいる仮想的な存在」のようなものである。
或いは、コードの実行されている行をちょこちょこ走る小人のようなものを想定しても良いだろう。
プログラマにとって身近なものでは、プログラムカウンタ(x86であればEIP
、x64であればRIP
)が近いかもしれない。