9

私は C の頭の体操に取り組んでいます。標準の Hello-World プログラムをセミコロンなしで書きます。

これまでの私の最良の答えは次のとおりです。

int main(void)
{
    if (printf("Hello World!\n"), exit(0), 0)
    {
        /* do nothing */
    }
}

しかし、コンパイラ エラーが発生しない理由がわかりません (Visual Studio):

error C4716: 'main' : must return a value

return-type が宣言されている他の関数を試しましたが、return-statement がありません。このコンパイラ エラーが発生します。


私も試したことに注意してください:

int foo(void)
{
    if (printf("Hello World!\n"), exit(0), true)
    {
        /* do nothing */
    }
}

int main(void)
{
    foo();
}

また、foo でコンパイラ エラーが発生しないようにします。「exit(0)」を削除するとコンパイラ エラーが発生します。どうやらコンパイラは「終了」が特別な機能であるという知識を持っていますか? これは私には非常に奇妙に思えます。

4

6 に答える 6

9

Jens がコメントで指摘したように、投稿されたコードは未定義の動作を示しません。ここでの元の答えは正しくなく、とにかく質問に答えているようには見えません(数年後にすべてを読み直したとき)。

main()この質問は、「MSVCは、他の機能と同じ状況で警告 C4716 を発行しないのはなぜですか」と要約できます。

診断 C4716 は警告であり、エラーではないことに注意してください。C 言語に関する限り (とにかく標準的な観点から)、エラー以外を診断する必要はありません。しかし、それはなぜ違いがあるのか​​ を実際に説明するものではありません。それは、あまり文句を言うことができないということを意味するかもしれない技術的なことです...

MSVC が他の機能に対して警告を発行するときに警告を発行しない理由の本当の説明はmain()、MSVC チームの誰かだけが実際に答えることができます。私が知る限り、ドキュメントは違いを説明していませんが、何かを見逃したのかもしれません。だから私にできることは推測することだけです:

C++ では、右中括弧の直前に main()暗黙的な関数があるという点で、関数は特別に扱われます。return 0;

Microsoft の C コンパイラは、C モードでコンパイルするときに同じ処理を提供すると思われます (アセンブリ コードを見ると、 がなくても EAX レジスタがクリアされますreturn 0;)、したがって、コンパイラに関する限り、発行する理由はありません。警告 C4716。Microsoft の C モードは C90 準拠であり、C99 準拠ではないことに注意してください。C90 では、「ru​​nning off the end」のmain()動作は未定義です。ただし、常に 0 を返すことは、未定義の動作の低い要件を満たしているため、問題はありません。

したがって、問題のプログラムが最後まで実行されたmain()としても (未定義の動作が発生した場合)、警告は表示されません。


元の、あまり良い答えではありません:

ANSI/ISO 90 C では、これは未定義の動作であるため、MS は実際にエラーを生成する必要があります (ただし、標準では要求されていません)。C99 では、returnC++ と同様に、標準で main() の最後に暗黙の を許可しています。

したがって、これが C++ または C99 としてコンパイルされている場合、エラーはなく、 と同じreturn 0;です。C90 では、未定義の動作が発生します (診断は必要ありません)。

興味深いことに (そうではないかもしれませんが)、いくつかのコンパイラ (VC9、VC6、GCC 3.4.5、Digital Mars、Comeau) の中で、基本的な、ほとんどがデフォルトのオプション セット (私がほとんど常に使用している環境) でこれを試してみました。コード スニペットの n-dirty テストなど)、return ステートメントの欠落について警告する唯一のコンパイラは、C++ プログラムとしてコンパイルするときに VC6 です (VC6 は、C 用にコンパイルするときに文句を言いません)。

関数に名前が付けられていない場合、ほとんどのコンパイラは文句を言います (警告またはエラー) main。C 用にコンパイルするときの Digital Mars はそうではなく、GCC は C または C++ 用にコンパイルしません。

于 2009-01-29T21:56:56.850 に答える
6

何も返さない場合、プログラムは 0 を返します。http://www.research.att.com/~bs/bs_faq2.html#void-mainを参照してください。

于 2009-01-29T21:13:24.647 に答える
2

コンパイルは、exit(0)が呼び出されていることを認識できるほど賢い場合があります。これは決して返されないため、必要ありません。

于 2009-01-29T21:16:35.810 に答える
1

これはエラーではないため、未定義の動作です。C99標準のセクション6.9.1、パラグラフ12を参照してください。

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

したがって、コンパイラは、コードが返されないのを確認したときに、自由に実行できます。エラー、警告、または何も出力されない可能性があります。GCCの場合、デフォルトでは、警告やエラーなしで正常にコンパイルされます。オプションを使用-Wallすると、警告が表示されます。

main()Cでは特別です。値を返さないことが許可されている唯一の関数です。C標準では、制御がステートメントmain()なしで終了に達するreturnと、暗黙的に0を返します。これは、にのみ当てはまりmain()、他のすべての非void関数は値を返す必要があります。

セクション5.1.2.2.3:

main関数のreturn型がintと互換性のある型である場合、main関数への最初の呼び出しからの戻りは、main関数によって返された値を引数としてexit関数を呼び出すことと同じです; 10)}に到達する終了メイン関数は値0を返します。戻りタイプがintと互換性がない場合、ホスト環境に返される終了ステータスは指定されていません。

于 2009-01-29T21:24:02.783 に答える
1

http://msdn.microsoft.com/en-us/library/k9dcesdd(VS.71).aspxから

C++ 言語リファレンス

出口機能

標準インクルード ファイル STDLIB.H で宣言されている exit 関数は、C++ プログラムを終了します。

exit の引数として指定された値は、プログラムのリターン コードまたは終了コードとしてオペレーティング システムに返されます。慣例により、ゼロの戻りコードは、プログラムが正常に完了したことを意味します。

注 STDLIB.H で定義されている定数 EXIT_FAILURE および EXIT_SUCCESS を使用して、プログラムの成功または失敗を示すことができます。

main 関数から return ステートメントを発行することは、戻り値を引数として exit 関数を呼び出すことと同じです。


于 2009-01-29T21:36:20.933 に答える
1

main から戻らない、またはより正確には、main 関数の終了 '}' に到達しないことは、さまざまな理由でまったく問題ありません。典型的なケースとしては、永遠にループすることや、前に終了または中止することが含まれます。

この場合、exit(0)main の最後に到達する前に が実行されることが保証されます。コンパイラが警告する必要があるのはなぜですか? これらに対する警告は期待できませんよね?

int main (void) { for (;;) { /* do something useful */ } }

int main (void) { /* do something  */; exit (0); }

私も驚くだろう

int main (void)
{
    if (printf("Hello World!\n"), exit(0), true)
    {
        /* do nothing */
    }
    return 0;
}

などの原因にはなりませんwarning: unreachable code: return 0

于 2012-05-12T16:30:47.970 に答える