web-dev-qa-db-ja.com

C関数の暗黙のint戻り値

私はグーグルで検索しましたが、この単純な質問に対する答えが見つからないようです。

レガシーコードベースで作業していて(最近Linuxに移植され、新しいコンパイラにゆっくりと更新されています)、

int myfunction(...)
{
// no return...
}

関数の暗黙の戻り値の型がintであることは知っていますが、戻り値が指定されていない場合の暗黙の戻り値は何ですか。私はテストして0を取得しましたが、それはgccでのみです。このコンパイラは固有ですか、それとも標準で0に定義されていますか?

編集:2017年12月標準のより新しいバージョンを参照することに基づいて、受け入れられた回答を調整しました。

27
LeviX

そのようなことは可能ですが、関数の戻り値が決して使用されないという仮定の下でのみです。 C11標準は6.9.1項で次のように述べています。

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

(標準の以前のバージョンのAFAIRにも同様の表現がありました)

したがって、その種のすべての関数をvoid関数に変換することをお勧めします。そうすれば、そのような関数のユーザーが戻り値を使用したくなることはありません。

9
Jens Gustedt

新約聖書で引用されている'89標準から:

関数の終わりから流れ出るのは、式のない戻りと同じです。いずれの場合も、戻り値は未定義です。

この標準は通常、既存の実装の現場での動作を表します。

21
dmckee

それは単に未定義の振る舞いです。戻り領域にデータを入力しない場合(たとえば、通常は x86ファミリプロセッサではeax/rax )、関数の副作用によって最後に設定された値になります。

voidを返さないC++関数にはreturnステートメントが必須ですか? これは基本的にこの質問の複製です(C++としてタグ付けされていることを除いて)。

10
modelnine

関数の戻り値の型がvoidでなくても、関数の最後でreturnステートメントが必須になることはありません。診断は不要であり、未定義の動作ではありません。

例(定義された動作):

int foo(void)
{
}

int main()
{
    foo();
}

ただし、fooの戻り値の読み取りは未定義の動作です。

int bla = foo();  // undefined behavior

C標準から:

(C99、6.9.1p12)「関数を終了する}に到達し、関数呼び出しの値が呼び出し元によって使用される場合、動作は未定義です。」

main関数はこのルールの例外です。main}に到達した場合は、return 0;ステートメントがあった場合と同等です。

8
ouah

returnステートメントが一貫して値を返さない場合、関数はvoidに変換され、次のように宣言されるのが最適です。

void myfunction(...)
{
    ...
    return;
    ...
}

関数にいくつかのreturn expr;ステートメントといくつかのreturn;ステートメントがある場合は、どちらがより良い動作であるかを判断し、それらを一貫させる必要があります。常に値を返し、型をintのままにするか、値を返さず、タイプをvoidに変更しないでください。

voidのデフォルトの戻り値の型(想定される戻り値の型)がなくなったため、staticを返すように変更された関数を宣言する必要があることに注意してください(それらがintであり、単一のソースファイルに隠されている場合を除きます)。有効です。

2

その関数では常にゼロになる可能性がありますが、ほとんどのアーキテクチャ(確かにx86)では、returnステートメントは、特定のレジスタの内容を、呼び出し元が取得してreturn関数として使用するスタック上の特定の場所に移動します。

Returnステートメントは、渡された変数をその場所に配置して、別の値になるようにします。特定のreturnステートメントを配置しないという私の経験では、返されるものはかなりランダムであり、同じものであると信頼することはできません。

1
dbeer

戻り値の型がvoidでない関数の場合、returnステートメントを省略することは未定義の動作であると確信しています。 C99では、mainの例外があり、returnステートメントが省略された場合、暗黙的に0を返すと見なされますが、これは他の関数には適用されません。

特定のプラットフォーム/コンパイラの組み合わせで動作する可能性がありますが、そのような詳細に依存しないでください。コードで未定義の動作を使用すると、移植できなくなります。ただし、レガシーコードで未定義の動作が見られるのはよくあることです。

0
dreamlax