main()はCおよびC ++で何を返す必要がありますか?


694

28
それでもかなり漠然としていると思います。私にとって「最も効率的な」と定義してください。どのような意味で効率的ですか?より少ないメモリを使用するという意味で?速く走るという意味では?有用な回答は表示されますが、質問の言い回しはかなり不十分だと思います。
Onorio Catenacci

7
ここでは、特に例(「効率的」の定義を明確にするためにある可能性があります)を使用して、効率的なコンテキストを明らかにします。うまく行かないと、貧弱なバッファが穴に潜り込んで質問を完全に後悔しなかったと思います。voidまたはintに関係なく値が返されるため、ファイルサイズ、実行される操作、割り当てられるメモリに影響を与えることはありません。また、ほとんどのOSで、成功した場合は0を返し、その他の場合は成功または失敗した場合に何かを返す傾向がありますが、標準はありません。最終的に、明らかな方法で効率に違いはありません。
キット

「正しい(最も効率的)」は意味がありません。効率が良いこともあれば、正しいこともある。mainが1回呼び出されます(C ++では1回しか呼び出せません:再帰なし)。実行に多くの時間を費やしたくない場合はmain、プログラムを何度も呼び出さないでください。プログラムに繰り返しを実装させます。
Kaz

2
答えがどれも、私の知る限り、#includeステートメントを含む完全に機能する例を提供していないことは興味深いと思います
puk

3
OSのないプラットフォームでは、戻り値は意味がありません。あなたは何にも戻らない。あなたがヒットした場合returnmain(...)埋め込まれたデバイス上で、お使いのシステムは、予測不可能な状態になり、あなたの洗濯機は、自己認識し、あなたを殺すためにしようとします。そのためvoid main()、その場合に使用します。これは、ベアメタル組み込みにおける業界標準の慣行です。
3Dave

回答:


569

の戻り値mainは、プログラムの終了方法を示します。通常の終了は、からの戻り値0で表されますmain。異常終了はゼロ以外の戻りによって通知されますが、ゼロ以外のコードの解釈方法に関する標準はありません。他の人が指摘したようにvoid main()、C ++標準では禁止されているため、使用しないでください。有効なC ++ main署名は次のとおりです。

int main()

そして

int main(int argc, char* argv[])

これは

int main(int argc, char** argv)

また、C ++では、int main()return-statementがなくてもかまいません。その場合、デフォルトで0が返されます。これは、C99プログラムにも当てはまります。return 0;省略すべきかどうかは議論の余地があります。有効なCプログラムのメインシグネチャの範囲ははるかに広いです。

効率はmain機能の問題ではありません。C ++標準に従って、1回だけ(プログラムの開始と終了をマークして)入力および終了できます。Cの場合、再入力main()は許可されていますが、回避する必要があります。


69
メインには複数回
出入り

13
C99には、main()関数の最後に到達すると0を返すのと同じであるというC ++の誤った機能もあります-main()がintと互換性のある型を返すように定義されている場合(セクション5.1.2.2.3)。
ジョナサンレフラー、

62
mainの再入力は有効なC ++ではありません。明示的に標準で、3.6.1.3州のメインは、プログラム内で使用してはならない"
workmad3

117
stdlib.hは、この目的のためにEXIT_SUCCESSおよびEXIT_FAILUREを提供します
クレイ

20
0と0以外は正しいですが、コードを読んでいる人にはまったく意味がありません。この質問は、人々が有効/無効なコードが何であるかを知らないことの証明です。EXIT_SUCCESS / EXIT_FAILUREはより明確です。
JaredPar 2008年

169

受け入れられた回答はC ++をターゲットにしているように見えるので、Cに関連する回答を追加すると思いましたが、これはいくつかの点で異なります。

ISO / IEC 9899:1989(C90):

main() 次のいずれかとして宣言する必要があります。

int main(void)
int main(int argc, char **argv)

または同等。たとえばint main(int argc, char *argv[])、2番目のものと同等です。また、int戻り値の型はデフォルトなので省略できます。

実装が許可する場合main()は、他の方法で宣言できますが、これによりプログラムの実装が定義され、厳密に準拠しなくなります。

この規格では、厳密に準拠している(つまり、実装で定義された動作に依存しない)戻り値0EXIT_SUCCESS、正常終了、およびEXIT_FAILURE異常終了の3つの値を定義しています。その他の値はすべて非標準であり、実装が定義されています。未定義の動作を回避するために、最後にmain()明示的なreturnステートメントが必要です。

最後に、main()プログラムからの呼び出しに関して、標準の観点からは何も問題はありません。

ISO / IEC 9899:1999(C99):

C99の場合、以下を除いてすべて上記と同じです。

  • int戻り値の型は省略することはできません。
  • からのreturnステートメントは省略できmain()ます。実行してmain()終了すると、暗黙のがありreturn 0ます。

1
@Lundin誰かが標準に準拠していないプログラムを受け入れるコンパイラを作成したり、stardardに準拠していないコンパイラを持つことを許可されていると言ったりするのに、引用が必要だとは思わない。それは常識と常識です
KABoissonneault 2015

4
@KABoissonneault実装定義の動作は、完全に文書化されていない動作とは対照的に、標準からの用語です。実装定義の動作としてリストされているものを実装する場合でも、標準に従います。引用されたこのケースでは、C89はそのような実装定義の動作を列挙していないため、引用符が必要であり、彼が突然に物事を作っているだけではないことを証明します。
ランディン、2015

1
@Lundinこれは間違った見方です。私たちが話しているのは、実装で定義された動作ではなく、標準から外れた実装を選択した場合です。それは、子供が親に反することのようなものです。親が言ったことに対して子供がどのように対抗できるかを伝えるために、親からの引用は必要ありません。子供がそうすることを選択した瞬間、彼らはもはや両親のガイドラインに準拠していないことを知っています
KABoissonneault 2015

2
@KABoissonneault私のコメントで引用した部分は、(非標準のコンパイラー拡張とは対照的に)実装定義の動作に関するものです。したがって、実装定義の動作について話しています。あなたが何か他のものについての独白を持っているなら、それで幸運を祈ります。
ランディン

1
@Lundin引用文の文言は紛らわしいと思いますが(「しかし、これによりプログラムの実装が定義されます」と言っている部分)、その人が非標準の動作について話していたと確信しています(「実装の場合それを許可し、実際の実装で定義された動作とは対照的に、「[厳密に[標準に準拠]することはもうありません」)。人は間違いなく答えを書き直すべきですが、それでも標準からの引用が必要であるとは思いません
KABoissonneault

117

標準C —ホスト環境

ホスト環境(通常の環境)の場合、C11標準(ISO / IEC 9899:2011)は次のように述べています。

5.1.2.2.1プログラムの起動

プログラムの起動時に呼び出される関数の名前はmainです。実装は、この関数のプロトタイプを宣言していません。これは、戻り値の型で定義され、intパラメータはありません。

int main(void) { /* ... */ }

または2つのパラメーター(ここでは、 argc andargvが、宣言されている関数に対してローカルであるため、任意の名前を使用できます):

int main(int argc, char *argv[]) { /* ... */ }

または同等のもの; 10)または他の実装定義の方法で。

それらが宣言されている場合、メイン関数のパラメーターは次の制約に従います。

  • の価値 argc負ないものとします。
  • argv[argc] ヌルポインタでなければならない。
  • の値がargcゼロより大きい場合、配列のメンバーargv[0]argv[argc-1]包括的にには、プログラムの起動前にホスト環境によって実装定義の値が与えられている文字列へのポインターが含まれます。その目的は、ホスト環境の他の場所からプログラムを起動する前に決定されたプログラム情報を提供することです。ホスト環境が文字列を大文字と小文字の両方で提供できない場合、実装は文字列が小文字で受信されるようにします。
  • の値がargcゼロより大きい場合、が指す文字列argv[0] はプログラム名を表します。argv[0][0]ホスト環境からプログラム名を取得できない場合は、ヌル文字になります。の値がargc1より大きい場合、argv[1]throughが指す文字列argv[argc-1] はプログラムパラメータを表します。
  • 配列が指すパラメーターargcargv文字列はargv、プログラムによって変更可能であり、プログラムの起動とプログラムの終了の間、最後に格納された値を保持します。

10)したがって、intとして定義されたtypedef名で置き換えることができますint。または、のタイプをargvとして記述することができます char **argv

C99またはC11でのプログラムの終了

から返された値はmain()、実装で定義された方法で「環境」に送信されます。

5.1.2.2.3プログラムの終了

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

11) 6.2.4に従って、自動ストレージ期間が宣言されたオブジェクトのライフタイムはmain 、前者の場合、後者の場合ではなくても終了します。

これ0は「成功」として義務付けられていることに注意してください。必要に応じてEXIT_FAILUREEXIT_SUCCESSfrom およびfrom を使用できます<stdlib.h>が、0は十分に確立され、1も確立されます。255より大きい終了コードも参照してください—可能ですか?

C89では(したがってMicrosoft Cでは)、main()関数が戻ったが戻り値を指定しなかった場合に何が起こるかについての記述はありません。したがって、未定義の動作につながります。

7.22.4.4 exit関数

¶5最後に、制御はホスト環境に戻されます。の値statusがゼロまたはの場合、EXIT_SUCCESSステータスが正常に終了したという、実装で定義された形式が返されます。値がいる場合statusEXIT_FAILURE、状況の実装定義フォームの失敗終了が返されます。それ以外の場合、返されるステータスは実装定義です。

標準C ++ —ホスト環境

C ++ 11標準(ISO / IEC 14882:2011)は次のように述べています。

3.6.1メイン関数[basic.start.main]

¶1プログラムは、プログラムの指定された開始点であるmainと呼ばれるグローバル関数を含まなければならない。[...]

¶2実装はmain関数を事前定義してはならない。この関数はオーバーロードしないでください。戻り型はint型ですが、それ以外の場合はその型は実装で定義されます。すべての実装は、以下のメインの定義の両方を許可するものとします。

int main() { /* ... */ }

そして

int main(int argc, char* argv[]) { /* ... */ }

後者の形式にargcは、プログラムが実行される環境からプログラムに渡される引数の数が含まれます。argcがゼロ以外の場合、これらの引数はnullで終了するマルチバイト文字列(NTMBS)(17.5.2.1.4.2)の最初の文字へのポインタとしてargv[0] throughから提供され、使用する名前を表すNTMBSの最初の文字へのポインタになります。プログラムを起動します。の値は負でないものとします。の値は 0です。[注:の後に、さらに(オプションの)パラメータを追加することをお勧めします。—エンドノート]argv[argc-1]argv[0]""argcargv[argc]argv

¶3関数mainはプログラム内で使用してはならない。のリンケージ(3.5)mainは実装定義です。[...]

¶5mainのreturnステートメントは、main関数を終了し(自動保存期間を持つオブジェクトを破棄)std::exit、引数として戻り値を使用して呼び出す効果があります。returnステートメントに遭遇せずに制御がメインの終わりに到達した場合、その効果は実行の結果です。

return 0;

C ++標準では、「[メイン関数]の戻り値の型はtype intでなければならないが、それ以外の場合はその型は実装で定義されている」と明記されており、C標準と同じ2つの署名をオプションとしてサポートする必要があります。したがって、「void main()」はC ++標準では直接許可されていませんが、非標準の実装を停止して代替を許可することはできません。C ++はユーザーによる呼び出しを禁止していることに注意してくださいmain(ただし、C標準では禁止されていません)。

C ++ 11標準には、§7.22.4.4 段落と同じである§18.5の開始と終了の段落があります。C11 標準exit関数(上記で引用)は、脚注(これは単に文書化されEXIT_SUCCESSEXIT_FAILURE定義されている)を除いてで<cstdlib>)。

標準C —共通拡張

古典的に、Unixシステムは3番目のバリアントをサポートします。

int main(int argc, char **argv, char **envp) { ... }

3番目の引数は、nullで終了する文字列へのポインタのリストです。それぞれのポインタは、名前、等号、および値(空の場合もある)を持つ環境変数です。これを使用しない場合でも、 ' extern char **environ;' を介して環境にアクセスできます。このグローバル変数は、それを宣言するヘッダーがないという点でPOSIXの変数の中で一意です。

これは、C規格によって、Annex Jに文書化されている共通の拡張機能として認識されています。

J.5.1環境引数

¶1ホストされた環境では、メイン関数は3番目の引数を受け取ります。この引数はchar *envp[]、nullで終了するへのポインターの配列を指しchar、それぞれがこのプログラムの実行環境に関する情報を提供する文字列を指します(5.1。 2.2.1)。

マイクロソフトC

マイクロソフトVS 2010コンパイラが面白いです。ウェブサイトは言う:

mainの宣言構文は次のとおりです

 int main();

または、オプションで

int main(int argc, char *argv[], char *envp[]);

または、mainand wmain関数をvoidreturn(戻り値なし)として宣言することもできます。void を宣言するmainwmain、またはvoidを返す場合、returnステートメントを使用して親プロセスまたはオペレーティングシステムに終了コードを返すことはできません。mainまたはwmainとして宣言されているときに終了コードを返すにはvoidexit関数を使用する必要があります。

のプログラムvoid main()が終了したときに何が起こるか(親またはOSにどの終了コードが返されるか)ははっきりしません。また、MS Webサイトもサイレントです。

興味深いことに、MSはmain()、CおよびC ++標準が必要とする2つの引数のバージョンを規定していません。3番目の引数がchar **envp環境変数のリストへのポインタである3つの引数形式のみを規定しています。

Microsoftのページにwmain()は、ワイド文字列など、他の選択肢もいくつかリストされています。

このページのMicrosoft Visual Studio 2005バージョンは、代替としてリストされていません。Microsoft Visual Studio 2008以降のバージョンで対応しています。void main()

標準C —独立型環境

前述のとおり、上記の要件はホスト環境に適用されます。(ホストされた環境の代替となる)独立した環境で作業している場合、標準は言うことはほとんどありません。独立した環境の場合、プログラムの起動時に呼び出される関数を呼び出す必要mainはなく、その戻り値の型に制約はありません。標準は言う:

5.1.2実行環境

自立型とホスト型の2つの実行環境が定義されています。どちらの場合も、指定されたC関数が実行環境によって呼び出されると、プログラムが起動します。静的な保存期間を持つすべてのオブジェクトは、プログラムの起動前に初期化(初期値に設定)されます。そうでなければ、そのような初期化の方法とタイミングは特定されていません。プログラムの終了により、実行環境に制御が戻ります。

5.1.2.1独立型環境

(Cプログラムの実行がオペレーティングシステムの利点なしに行われる可能性がある)独立した環境では、プログラムの起動時に呼び出される関数の名前とタイプは実装定義です。4節で必要とされる最小セット以外の、独立型プログラムで使用可能なライブラリ機能は、実装定義です。

独立した環境でのプログラム終了の影響は、実装によって定義されます。

第4項の適合性への相互参照はこれを参照します。

¶5 厳密に準拠するプログラムは、この国際標準で指定されている言語およびライブラリの機能のみを使用するものとします。3)未指定、未定義、または実装定義の動作に依存する出力を生成せず、最小実装制限を超えてはなりません。

¶6適合する実装の2つの形式は、ホスト独立型です。準拠したホストされた実装では、任意の厳密に準拠するプログラムを受け入れるもの。適合自立実装では、ライブラリ句(項7)で指定された機能の使用は、標準ヘッダの内容に限定される任意の厳密に適合するプログラムを受け入れなければならない<float.h><iso646.h><limits.h><stdalign.h><stdarg.h><stdbool.h><stddef.h><stdint.h>、および <stdnoreturn.h>。厳密に準拠するプログラムの動作を変更しない限り、準拠する実装に拡張機能(追加のライブラリ関数を含む)が含まれる場合があります。4)

¶7 適合プログラムは、適合実装に受け入れられるプログラムです。5)

3)厳密に準拠するプログラムは、条件付き機能(6.10.8.3を参照)を使用できます。ただし、関連するマクロを使用する適切な条件付き包含前処理指令によって使用が保護されている場合に限ります。例えば:

#ifdef __STDC_IEC_559__ /* FE_UPWARD defined */
    /* ... */
    fesetround(FE_UPWARD);
    /* ... */
#endif

4)これは、準拠する実装が、この国際標準で明示的に予約されている識別子以外の識別子を予約しないことを意味します。

5)厳密に準拠するプログラムは、準拠する実装間で最大限に移植できるように意図されています。適合プログラムは、適合実装の非移植機能に依存する場合があります。

機能を実際に定義する独立した環境に必要なヘッダーは唯一であることに注意してください<stdarg.h>(さらに、それらはマクロである場合もあり、多くの場合は単なるマクロです)。

標準C ++ —独立型環境

C標準がホスト環境と独立環境の両方を認識するように、C ++標準も同様です。(ISO / IEC 14882:2011からの引用)

1.4実装コンプライアンス[intro.compliance]

¶72種類の実装が定義されています:ホストされた実装独立した実装です。ホストされた実装の場合、この国際標準は利用可能なライブラリのセットを定義します。独立した実装とは、オペレーティングシステムの利点なしに実行が行われる可能性がある実装であり、特定の言語サポートライブラリ(17.6.1.3)を含む実装定義のライブラリセットがあります。

¶8適合した実装は、整形式プログラムの動作を変更しない限り、拡張機能(追加のライブラリ関数を含む)を持つ場合があります。この国際標準に従って不適切な形式の拡張機能を使用するプログラムを診断するには、実装が必要です。ただし、そうすることで、そのようなプログラムをコンパイルして実行できます。

¶9各実装は、それがサポートしないすべての条件付きでサポートされる構成を識別し、すべてのロケール固有の特性を定義するドキュメントを含むものとします。

3)このドキュメントは、実装定義の動作も定義しています。1.9を参照してください。

17.6.1.3独立型の実装[コンプライアンス]

ホスト型と独立型の実装の2種類が定義されています(1.4)。ホストされた実装の場合、この国際標準は利用可能なヘッダーのセットを記述します。

独立した実装には、実装で定義された一連のヘッダーがあります。このセットには、少なくとも表16に示すヘッダーが含まれます。

ヘッダの供給されたバージョンは、<cstdlib>少なくとも関数を宣言しなければならないabortatexitat_quick_exitexit、およびquick_exit(18.5)。この表にリストされている他のヘッダーは、ホストされる実装の場合と同じ要件を満たしている必要があります。

表16 —独立型実装のC ++ヘッダー

Subclause                           Header(s)
                                    <ciso646>
18.2  Types                         <cstddef>
18.3  Implementation properties     <cfloat> <limits> <climits>
18.4  Integer types                 <cstdint>
18.5  Start and termination         <cstdlib>
18.6  Dynamic memory management     <new>
18.7  Type identification           <typeinfo>
18.8  Exception handling            <exception>
18.9  Initializer lists             <initializer_list>
18.10 Other runtime support         <cstdalign> <cstdarg> <cstdbool>
20.9  Type traits                   <type_traits>
29    Atomics                       <atomic>

int main()Cでの使用についてはどうですか?

C11標準の標準§5.1.2.2.1は推奨される表記法を示しています—  int main(void)—しかし、標準には次の2つの例がありますint main()§6.5.3.4¶8§6.7.6.3¶20。ここで、例は「規範的」ではないことに注意することが重要です。これらは単なる例示です。例にバグがあっても、標準の本文には直接影響しません。とは言っても、それらは予想される動作を強く示しているため、標準にint main()例が含まれている場合、それがint main()推奨される表記法でなくても禁止されていないことを示唆しています。

6.5.3.4 sizeofand _Alignof演算子

¶8例3この例では、可変長配列のサイズが計算され、関数から返されます。

#include <stddef.h>

size_t fsize3(int n)
{
    char b[n+3]; // variable length array
    return sizeof b; // execution time sizeof
}
int main()
{
    size_t size;
    size = fsize3(10); // fsize3 returns 13
    return 0;
}

@DavidBowling:のような関数定義int main(){ … }は、関数が引数を取らないことを指定しますが、関数プロトタイプAFAICTを提供しません。以下のためにmain()その問題はほとんどありません。つまり、への再帰呼び出しがあるmain()場合、引数はチェックされません。他の関数の場合は、それが問題になります。引数が正しいことを確認するには、関数を呼び出すときにスコープ内にプロトタイプが本当に必要です。
Jonathan Leffler 2017

1
@DavidBowling:通常main()、IOCCCのような場所以外では、再帰的に呼び出すことはありません。私はそれを行うテストプログラムを持っています—主に新規性のためです。あなたが持っている場合int i = 0; int main() { if (i++ < 10) main(i, i * i); return 0; }やGCCでコンパイルすると、含まれていません-Wstrict-prototypes、それは厳しい警告の下にきれいにコンパイルされます。の場合main(void)、コンパイルに失敗します。
Jonathan Leffler 2017

61

またはのmain()いずれかが返されると思います。それらはで定義されていますEXIT_SUCCESSEXIT_FAILUREstdlib.h


20
0も標準です。
クリスヤング

2
@ChrisYoungがあるEXIT_SUCCESSEXIT_FAILURE、いくつかの歴史的なオペレーティング・システム(VMS?)理由を示して成功に0以外の数字を使用していました。今日はどこでも0です。
fuz

5
@FUZxxlあなたは正しいですが、それは私のコメントと矛盾しません。EXIT_SUCCESSは実際にはゼロ以外でもかまいませんが、標準(C89、C99、C11)はすべて0(およびEXIT_SUCCESS)を実装定義のステータス成功終了の形式と定義しています。
Chris Young

2
@FUZxxl:VMSが成功を示すために奇数値(1など)を使用し、失敗を示すために偶数値(0など)を使用したことは事実です。残念ながら、元のANSI C標準では、EXIT_SUCCESSを0にする必要があると解釈されていたため、メインからEXIT_SUCCESSを返すと、VMSで正確に正しく動作しませんでした。VMSで行うポータブルなことは、exit(EXIT_SUCCESS)常に正しいことを行うを使用することでした。
エイドリアン・マッカーシー

1
5.1.2.2.3「メイン関数の戻り値の型がintと互換性のある型である場合、メイン関数への最初の呼び出しからの戻りは、引数としてメイン関数によって返された値を使用して出口関数を呼び出すことと同等です。 11)メイン関数を終了する}に到達すると、値0が返されます。 "
ランディン

38

CおよびC ++標準は、2種類の実装を定義していることに注意してください:独立型とホスト型。

  • C90ホスト環境

    許可されるフォーム1

    int main (void)
    int main (int argc, char *argv[])
    
    main (void)
    main (int argc, char *argv[])
    /*... etc, similar forms with implicit int */

    コメント:

    前者の2つは許可された形式として明示的に示され、その他は暗黙的に許可されます。これは、C90が戻り値の型と関数パラメーターに「暗黙のint」を許可したためです。他のフォームは許可されていません。

  • C90自立型環境

    メインの任意の形式または名前を使用できます2

  • C99ホスト環境

    許可されるフォーム3

    int main (void)
    int main (int argc, char *argv[])
    /* or in some other implementation-defined manner. */

    コメント:

    C99は「implicit int」を削除したためmain()、無効になりました。

    「またはその他の実装定義の方法で」奇妙で曖昧な文が導入されました。これは、「パラメーターint main()が異なる可能性がある」または「メインが任意の実装定義の形式を持つことができる」と解釈できます。

    一部のコンパイラは、標準を後者の方法で解釈することを選択しています。規格があいまいなので、規格自体を引用しても、厳密に準拠していないとは言い難いことは間違いありません。

    ただし、完全にワイルドな形式を許可することmain()は、おそらくこの新しい文の意図ではありませんでしたか(?)。C99の理論的根拠(規範的ではない)は、文がint main 4への追加のパラメーターを参照していることを意味します。

    それでも、ホスト環境プログラムの終了に関するセクションでは、mainがint 5を返さない場合について議論を続けています。そのセクションはmainの宣言方法の規範ではありませんが、ホストシステムでもmainが完全に実装定義の方法で宣言される可能性があることを明確に意味します。

  • C99自立型環境

    メインの任意の形式または名前を使用できます6

  • C11ホスト環境

    許可されるフォーム7

    int main (void)
    int main (int argc, char *argv[])
    /* or in some other implementation-defined manner. */
  • C11自立型環境

    メインの任意の形式または名前を使用できます8


int main()上記のバージョンのいずれにおいても、Cのホストされた実装の有効な形式としてリストされたことがないことに注意してください。Cでは、C ++ ()(void)は異なり、意味が異なります。前者は廃止された機能であり、言語から削除される可能性があります。C11の将来の言語指示を参照してください。

6.11.6関数宣言子

括弧が空の関数宣言子(プロトタイプ形式のパラメーター型宣言子ではない)の使用は、廃止された機能です。


  • C ++ 03ホスト環境

    許可されるフォーム9

    int main ()
    int main (int argc, char *argv[])

    コメント:

    最初のフォームの空の括弧に注意してください。この場合、C ++とCは異なります。これは、C ++では関数がパラメーターを取らないことを意味するためです。しかし、Cでは、任意のパラメーターを取ることができることを意味します。

  • C ++ 03自立環境

    起動時に呼び出される関数の名前は実装定義です。名前が付けられmain()ている場合は、指定されたフォーム10に従う必要があります。

    // implementation-defined name, or 
    int main ()
    int main (int argc, char *argv[])
  • C ++ 11ホスト環境

    許可されるフォーム11

    int main ()
    int main (int argc, char *argv[])

    コメント:

    標準のテキストは変更されましたが、同じ意味です。

  • C ++ 11自立環境

    起動時に呼び出される関数の名前は実装定義です。名前が付けられmain()ている場合は、指定された形式12に従う必要があります。

    // implementation-defined name, or 
    int main ()
    int main (int argc, char *argv[])

参考文献

  1. ANSI X3.159-1989 2.1.2.2ホスト環境。「プログラムの起動」

    プログラムの起動時に呼び出される関数の名前はmainです。実装は、この関数のプロトタイプを宣言していません。これはintの戻り型で定義され、パラメーターはありません。

    int main(void) { /* ... */ } 

    または2つのパラメーター(ここではargcおよびargvと呼ばれますが、宣言された関数に対してローカルであるため、どのような名前でも使用できます):

    int main(int argc, char *argv[]) { /* ... */ }
  2. ANSI X3.159-1989 2.1.2.1独立型環境:

    (Cプログラムの実行がオペレーティングシステムの利点なしに行われる可能性がある)独立した環境では、プログラムの起動時に呼び出される関数の名前とタイプは実装定義です。

  3. ISO 9899:1999 5.1.2.2ホスト環境-> 5.1.2.2.1プログラムの起動

    プログラムの起動時に呼び出される関数の名前はmainです。実装は、この関数のプロトタイプを宣言していません。これはintの戻り型で定義され、パラメーターはありません。

    int main(void) { /* ... */ } 

    または2つのパラメーター(ここではargcおよびargvと呼ばれますが、宣言された関数に対してローカルであるため、どのような名前でも使用できます):

    int main(int argc, char *argv[]) { /* ... */ }

    または同等のもの; 9)またはいくつかの他の実装定義方法で。

  4. 国際標準の根拠—プログラミング言語— C、リビジョン5.10。5.1.2.2ホスト環境-> 5.1.2.2.1プログラムの起動

    mainへの引数の動作と、exit、main、およびatexit(§7.20.4.2を参照)の相互作用の動作は、argv文字列の表現とmainから返される値の意味のいくつかの不要な変化を抑制するために体系化されました。

    mainへの引数としてのargcおよびargvの仕様は、広範な従来の慣行を認識しています。argv [argc]は、これも一般的な慣行に基づいて、リストの最後の冗長チェックを提供するためにnullポインターである必要があります。

    mainは、ゼロまたは2つの引数を使用して移植可能に宣言できる唯一の関数です。(他の関数の引数の数は、呼び出しと定義の間で正確に一致している必要があります。)この特別なケースは、プログラムがプログラムの引数文字列にアクセスしないときに、引数をmainに渡さないという広く行われている方法を単に認識します。多くの実装はmainへの3つ以上の引数をサポートしていますが、そのような慣行は規格によって祝福されたり禁止されたりしていません。3つの引数でmainを定義するプログラムは、厳密に準拠していません(§J.5.1を参照)。

  5. ISO 9899:1999 5.1.2.2ホスト環境-> 5.1.2.2.3プログラムの終了

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

  6. ISO 9899:1999 5.1.2.1独立型環境

    (Cプログラムの実行がオペレーティングシステムの利点なしに行われる可能性がある)独立した環境では、プログラムの起動時に呼び出される関数の名前とタイプは実装定義です。

  7. ISO 9899:2011 5.1.2.2ホスト環境-> 5.1.2.2.1プログラムの起動

    このセクションは、上記のC99と同じです。

  8. ISO 9899:1999 5.1.2.1独立型環境

    このセクションは、上記のC99と同じです。

  9. ISO 14882:2003 3.6.1主な機能

    実装はメイン関数を事前定義してはなりません。この関数はオーバーロードしないでください。戻り型はint型ですが、それ以外の場合は型は実装定義です。すべての実装は、以下のメインの定義の両方を許可するものとします。

    int main() { /* ... */ }

    そして

    int main(int argc, char* argv[]) { /* ... */ }
  10. ISO 14882:2003 3.6.1主な機能

    メイン関数を定義するために自立環境のプログラムが必要かどうかは、実装定義です。

  11. ISO 14882:2011 3.6.1主な機能

    実装はメイン関数を事前定義してはなりません。この関数はオーバーロードしないでください。戻り型はint型ですが、それ以外の場合は型は実装定義です。すべての実装で両方を許可する

    —()の関数がintを返す

    —(int、charへのポインタへのポインタ)の関数がintを返す

    メインのタイプとして(8.3.5)。

  12. ISO 14882:2011 3.6.1主な機能

    このセクションは、上記のC ++ 03と同じです。


1つの質問:C ++標準は、自立型環境でのスタートアップ関数のシグネチャも実装で定義されることを意味しますか?例えば、実装があることをスタートアップ関数を定義することも可能です。int my_startup_function ()あるいはint my_startup_function (int argc, char *argv[])それが持つことができ、例えば:char my_startup_function (long argc, int *argv[])スタートアップ関数と同様?違いますよね?また、それもあいまいではありませんか?
Utku、2015年

@Utku名前が指定されていない限りmain()、リストにある署名の1つを使用する必要があるため、任意の署名を付けることができます。void my_startup_function ()自立型システムのプログラムから戻るのは意味がないので、圧倒的に最も一般的なのはだろうと思います。
ランディン

1
そうですか。しかし、スタートアップ関数に任意の名前と署名を使用することが許可されている場合は、別の署名を使用することも許可しないのはなぜmainですか?賢明な質問ではない場合は申し訳ありませんが、背後にある理由を理解できませんでした。
Utku、2015年

@Utku CとC ++はそこで異なります。C ++がこれを強制する理由については、私にはわかりません。根拠はありません。私は、主な犯人(しゃれが意図的)が、初期に主人がint、periodを返さなければならないと宣言したStroustrupであると思います。彼が最初のC ++バージョンを作ったとき、彼はホストされたシステムにしか使用されていなかったからです。リンクされた投稿では、Stroustrupはまだ独立した実装の存在に気づいていないようです。たとえば、5.1.2.1の存在を無視して、C標準のホストされた実装のサブチャプターを無意識に参照しています。
ランディン、2015年

1
C11標準ドラフトの注目すべき点は、func()廃止されたと見なされていても、ドラフト自体がint main()独自の例で使用されていることです。
Antti Haapala 2016年

29

成功した場合は0を返し、エラーの場合はゼロ以外を返します。これは、プログラムで何が起こったかを調べるためにUNIXおよびDOSスクリプトで使用される標準です。


8

main() C89およびK&R Cでは、未指定の戻り値の型はデフォルトで「int」に設定されます。

return 1? return 0?
  1. でreturnステートメントを記述しない場合int main()、終了{はデフォルトで0を返します。

  2. return 0またはreturn 1親プロセスによって受信されます。シェルでは、シェル変数に入ります。プログラムをシェルから実行していて、その変数を使用していない場合は、の戻り値を気にする必要はありませんmain()

メイン関数から返されたものを取得するにどうすればよいですか?を参照してください

$ ./a.out
$ echo $?

これ$?により、の戻り値の最下位バイトを受け取るのは変数であることがわかりますmain()

UnixおよびDOSスクリプティングでreturn 0は、通常、成功するとゼロ以外のエラーが返されます。これは、プログラムで何が起こったかを調べ、フロー全体を制御するためにUnixおよびDOSスクリプトで使用される標準です。


4
厳密に言えば、$?は環境変数ではありません。これはシェルの事前定義(または組み込み)変数です。違いを見つけるのは難しいですが、env(引数なしで)実行すると、環境が出力$?され、環境には表示されません。
ジョナサンレフラー2013

1
メインの「終わりの落下」がC ++とC99以降でのみ発生し、C90では発生しない場合に自動的に0を返す
Kaz

タイプミス:「終了{」はである必要があります}。SOでは、これほど小さな編集はできません。
スペンサー

7

intを返す場合でも、一部のOS(Windows)は戻り値を1バイト(0-255)に切り捨てることを覚えておいてください。


4
Unixも、おそらく他のほとんどのオペレーティングシステムと同じように動作します。VMSが非常に奇妙なことを実行し、EXIT_SUCCESSまたはEXIT_FAILURE以外のものを返すと問題が発生することを知っています。
Leon Timmermans

2
MSDNは異なることを要求します:mscorlibを通じて報告される場合、終了コードは符号付き32ビット整数です。これは、終了コードを切り捨てるCランタイムライブラリに欠陥があることを意味しているようです。

はい、これは誤りです。Windowsでは、32ビット整数が返されます(そしてに変換されますunsigned)。これは、32ビット整数のUNIXシステムでも同じです。ただし、どちらのシステムのUNIXスタイルのシェルも、通常、符号なし8ビット整数のみを保持します。
ジョンマクファーレン

4

オペレーティングシステムは、戻り値を使用して、プログラムがどのように閉じられたかを確認できます。

戻り値0は通常、ほとんどのオペレーティングシステム(とにかく考えることができるもの)でOKを意味します。

また、自分でプロセスを呼び出すときにチェックして、プログラムが正常に終了して終了したかどうかを確認することもできます。

これは単なるプログラミング規約ではありません


手術システムが存在することを示す質問には何もありません。独立したシステムでは、値を返すことは意味がありません。
ランディン、2015

3

の戻り値はmain()、プログラムがどのように終了したかを示します。戻り値の場合はzero、実行が成功したことを意味しますが、ゼロ以外の値は、実行中に問題が発生したことを表します。


1
これは質問に対する回答ではなくコメントです。
ランディン、2015

2

標準では、正常な戻り値はOSベースであるため、戻り値は不要であると規格が規定しているという印象を受けました(1つのゼロは別の成功または失敗のいずれかである可能性があります)。成功したリターン自体を挿入するコンパイラ。

ただし、通常は0を返します。


C99(およびC ++ 98)では、mainからreturnステートメントを省略できます。C89では、returnステートメントを省略できません。
ジョナサンレフラー2013

これは回答ではなくコメントです。
ランディン、2015

これは質問に対する答えを提供しません。批評したり、著者に説明を求める場合は、投稿の下にコメントを残してください。
Steve Lillis、2015

6
@SteveLillis:2008年、SOにはコメントセクションがありませんでした。
graham.reeds 2015

2

0を返すと、プログラムがジョブを正常に終了したことをプログラマーに伝える必要があります。


main()通常から1を返すと、エラーが発生したことを示します。0を返すと成功を示します。プログラムが常に失敗する場合、1は問題ありませんが、最善の方法ではありません。
ジョナサンレフラー2013

1
@JonathanLeffler:1から戻ることの意味mainは実装定義です。唯一の言語に定義されている値は0EXIT_SUCCESS(多くの場合のように定義0)、およびEXIT_FAILURE。OpenVMSでは、正常終了をreturn 1;示します。
キース・トンプソン

VMSは「正常」ではありません—私が言ったことの意味の範囲内です。「奇妙な価値は成功です。VMSでも値は失敗しますか?
Jonathan Leffler、2014

2

省略 return 0

CまたはC ++プログラムが最後に到達するとmain、コンパイラーは自動的にコードを生成して0を返すためreturn 0;、の最後に明示的に配置する必要はありませんmain

注:私がこの提案をすると、ほぼ常に2種類のコメントのうちの1つが続きます:「私はそれを知りませんでした。」または「それは悪いアドバイスです!」私の理論的根拠は、標準で明示的にサポートされているコンパイラの動作に依存することが安全で便利だということです。Cの場合、C99以降。ISO / IEC 9899:1999セクション5.1.2.2.3を参照してください。

[...]最初のmain関数呼び出しからのexit戻りは、main関数によって返された値を引数として関数を呼び出すことと同じです。関数}を終了するに到達するとmain、値0が返されます。

C ++の場合、1998年の最初の標準以降。ISO / IEC 14882:1998セクション3.6.1を参照してください。

制御がreturnステートメントに出会わずにメインの終わりに到達した場合、その効果はreturn 0を実行することです。

それ以降の両方の標準のすべてのバージョン(C99およびC ++ 98)は同じ考えを維持しています。私たちはC ++で自動的に生成されるメンバー関数に依存しておりreturn;void関数の最後に明示的なステートメントを書く人はほとんどいません。省略しない理由は、「奇妙に見える」に要約されるようです。私のように、C標準への変更の論理的根拠に興味があるなら、この質問を読んでください。また、1990年代の初めには、これは(広くサポートされていますが)未定義の動作だったため、「だらしない習慣」と見なされていたことにも注意してください。

さらに、C ++コアガイドラインにreturn 0;、末尾の省略の複数のインスタンスが含まれていますmainれており、明示的なリターンが書き込まれていません。その文書のこの特定のトピックに関する特定のガイドラインはまだありませんが、それは少なくとも練習の暗黙の裏書と思われます。

だから私はそれを省略することを提唱しています。他の人は同意しない(しばしば激しく!)いずれにせよ、それを省略するコードに遭遇した場合、そのコードが標準によって明示的にサポートされていることがわかり、その意味がわかります。


2
後の標準ではなくC89のみを実装するコンパイラーは依然として非常に一般的であり(2017年にこれを書いている)、これは当面は非常に一般的であるため、これは悪いアドバイスです。たとえば、最後にチェックしたのは、C99を実装したMicrosoftのコンパイラのバージョンがないことです。これは、GCC以外の組み込みシステムコンパイラでもまだ一般的であることを理解しています。
zwol 2017年

4
@zwol:28年前に古くなっているコンパイラを使用せざるを得ない人はreturn 0;、明示的にインクルードするかどうかを決定するよりもおそらく問題が多くありますが、その時代の多くのコンパイラreturn 0;も、以前よりも暗黙的に実装されていることに注意します標準化された。
エドワード

2
実際、私は多くの組み込みシステムの作業を行ってreturn 0おり、10年以上、暗黙をサポートしていないコンパイラーに遭遇していません。また、現在のバージョンのMicrosoft Cもサポートしています。おそらくあなたの情報は古くなっていますか?
エドワード

2
私はこれがCで議論の余地があることを認めることができます。C ++では、これをめぐる論争はまったくナンセンスです。
Orbitのライトネスレース

2
@エドワード私は論争が存在しないとは言わなかった、それはナンセンスだと私は言った:P
オービットでの軽さの

1

何を返すかは、実行可能ファイルをどのように処理するかによって異なります。たとえば、プログラムをコマンドラインシェルで使用している場合、成功した場合は0を返し、失敗した場合は0以外を返す必要があります。次に、コードの結果に応じて、条件付き処理を伴うシェルでプログラムを使用できます。また、解釈に応じてゼロ以外の値を割り当てることもできます。たとえば、重大なエラーの場合、さまざまなプログラムの終了ポイントがさまざまな終了値でプログラムを終了させる可能性があり、返された値を検査することによって何を行うかを決定できる呼び出し側シェルで使用できます。コードがシェルでの使用を意図しておらず、戻り値がだれも気にしない場合は、省略される可能性があります。個人的に署名を使用していますint main (void) { .. return 0; .. }


main()のフォーマットは、コンパイラーを意味する実装によって決定されます。コンパイラーがいくつかのフォームをサポートしている場合を除いて、プログラマーはどのフォームを選択するかを選択しません。
ランディン

@Lundin戻り値の型は実装によって実装されます。ただし、返される値はプログラマーが決定します。C99セクション5.1.2.2.3では、の戻り値の型はmainと互換性があると述べていintます。したがって、戻るintことは問題になりません。他の戻り値の型も許可されますが、その場合、戻り値を持つ環境変数は指定されません。しかし、プログラマがreturn 0;bashで行う場合は、ブランチを作成するために使用できます。
phoxis 2017

1

プロセスから整数を返す効率に関連する問題が本当にある場合は、そのプロセスを何度も呼び出して、この戻り値が問題になることを避ける必要があります。

これを実行している場合(プロセスを何度も呼び出す場合)、呼び出しごとに特定のプロセスを割り当てずに、呼び出し元内またはDLLファイルに直接ロジックを配置する方法を見つける必要があります。この場合、複数のプロセス割り当てにより、関連する効率の問題が発生します。

詳細には、0を返すのが1を返すよりも多かれ少なかれ効率的であるかどうかを知りたいだけなら、場合によってはコンパイラーに依存する可能性がありますが、一般的に、同じソース(ローカル、フィールド、定数、埋め込み)から読み取られると想定します。コード、関数結果など)では、まったく同じ数のクロックサイクルが必要です。


1

ここに戻りコードの使用法の小さなデモがあります...

Linuxターミナルが提供するさまざまなツールを使用する場合、たとえば、プロセスが完了した後のエラー処理などに戻りコードを使用できます。次のテキストファイルmyfileがあるとします。

これは、grepの動作を確認するためのいくつかの例です。

grepコマンドを実行すると、プロセスが作成されます。処理が完了すると(壊れることはありません)、0〜255のコードが返されます。次に例を示します。

$ grep order myfile

もしあなたがそうするなら

$ echo $?
$ 0

あなたは0を取得します。なぜですか?ためのgrepは一致を見つけ、成功で終了するための通常の値である終了コード0を返さ。もう一度確認してみましょう。ただし、テキストファイル内にないため、一致するものが見つかりません。

$ grep foo myfile
$ echo $?
$ 1

grepがトークン "foo"とファイルのコンテンツを照合できなかったため、戻りコードは1です(これは通常、失敗が発生した場合ですが、前述のように、選択できる値がたくさんあります)。

次のbashスクリプト(Linuxターミナルで単純に入力)は非常に基本的なものですが、エラー処理についていくつかのアイデアを提供します。

$ grep foo myfile
$ CHECK=$?
$ [ $CHECK -eq 0] && echo 'Match found'
$ [ $CHECK -ne 0] && echo 'No match was found'
$ No match was found

"foo"がgrepを1に戻したため、2行目以降はターミナルに何も出力されず、grepの戻りコードが0に等しいかどうかを確認します。 == 1。

これとそのプロセスを呼び出しているかどうかを確認できるように、(main()の戻り値によって)何が返されたかを確認することが不可欠な場合があります。


シェルスクリプトではif grep foo myfile; then echo 'Match found'; else echo 'No match was found'; fi、リターンステータスを直接テストして使用します。(レポートなどのために)ステータスをキャプチャする場合は、割り当てを使用します。使用するif grep foo myfile; CHECK=$?; [ "$CHECK" = 0 ]; then echo 'Match found'; else echo 'No match was found'; fi場合もあれば、3行を使用する場合もあります。オプション-s-qを使用しgrepて、一致または定期的なエラーメッセージが表示されないようにすることもできます。ただし、これはシェルの特徴点であり、終了ステータスが役立つという重要なポイントですが、問題ありません。
ジョナサンレフラー

1

CおよびC ++でmain()関数を定義する正しい(最も効率的な)方法は何ですか— int main()またはvoid main()—なぜですか?

「(最も効率的)」という言葉は問題を変えません。自立した環境にいない限り、を宣言する普遍的に正しい方法が1つあり、それはmain()intを返すことです。

main()CおよびC ++では何を返す必要がありますか?

それは何ではないはずです main()、それは何だ、返さない main()リターンを。 main()もちろん、他の誰かが呼び出す関数です。を呼び出すコードを制御することはできませんmain()。したがって、main()呼び出し元と一致するように、タイプが正しい署名で宣言する必要があります。あなたは単にその問題について何の選択肢もありません。CとC +の標準によって答えがすでに完全に明確に定義されているため、効率の良し悪し、スタイルの良し悪し、またはそのようなものを自問する必要はありません。それらに従ってください。

int main()の場合、1を返すか、0を返しますか?

成功の場合は0、失敗の場合はゼロ以外。繰り返しになりますが、選択する(または取得する)必要のあるものではありません。これは、準拠しているはずのインターフェイスによって定義されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.