web-dev-qa-db-ja.com

Cのmain()関数の有効な署名は何ですか?

Cのメイン関数の有効な署名とは何ですか?知っている:

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

他に有効なものはありますか?

56
Prady

この回答(C11)の時点での現在の標準では、次の2つが明示的に言及されています。

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

ただし、次の脚注で「または同等の」フレーズに言及しています。

したがって、inttypedefとして定義されたintの名前に置き換えるか、argvのタイプをchar ** argvとして記述できます。など。

さらに、より多くの(実装定義)可能性も提供します。

関連セクション(C11セクション5.1.2.2.1、ただしこの特定の側面はC99から変更されていない)には次のように記載されています。

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

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

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

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

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

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

  • argcの値は非負でなければなりません。

  • argv[argc]はNULLポインターでなければなりません。

  • argcの値がゼロより大きい場合、配列メンバーargv[0]argv[argc-1]には、プログラムの前にホスト環境によって実装定義の値が与えられる文字列へのポインターが含まれます。起動。その目的は、ホストされた環境のどこからでもプログラムの起動前に決定された情報をプログラムに提供することです。ホスト環境が大文字と小文字の両方で文字を含む文字列を提供できない場合、実装は文字列が小文字で受信されることを保証する必要があります。

  • argcの値がゼロより大きい場合、argv[0]が指す文字列はプログラム名を表します。プログラム名がホスト環境から利用できない場合、argv[0][0]はヌル文字でなければなりません。 argcの値が1より大きい場合、argv[1]からargv[argc-1]が指す文字列はプログラムパラメーターを表します。

  • パラメータargcおよびargvおよびargv配列が指す文字列は、プログラムで変更可能であり、プログラムの起動と終了の間で最後に保存された値を保持します。

これは、Cプログラムで通常表示されるホスト環境用です。同じ標準の5.1.2.1で述べられているように、独立した環境(組み込みシステムなど)の制約ははるかに少なくなっています。

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

66
paxdiablo

標準C

ホスト環境(通常の環境)の場合、C99標準では次のように記述されています。

5.1.2.2.1プログラムの起動

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

_int main(void) { /* ... */ }
_

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

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

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

9) したがって、intintとして定義されたtypedef名に置き換えることができます。また、argvの型は_char **argv_などと書くことができます。

C11およびC18規格は、C99規格と本質的に同じと言っています。

標準C++

C++ 98標準には次のように書かれています。

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

1プログラムには、プログラムの指定された開始であるmainというグローバル関数が含まれます。 [...]

2実装は、メイン機能を事前定義してはなりません。この機能はオーバーロードされません。戻り値の型はintですが、それ以外の場合、その型は実装定義です。すべての実装は、mainの以下の定義の両方を許可します:

_int main() { /* ... */ }
_

そして

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

C++標準は、「それ(メイン関数)は戻り値の型はintでなければならないが、そうでなければその型は実装定義である」と明示的に述べ、C標準と同じ2つの署名を必要とします。したがって、「void main()」はC++標準では直接許可されていませんが、非標準準拠の実装が代替を許可するのを止めることはできません(標準準拠の実装が代替を標準の拡張として許可することもできません)。

C++ 03、C++ 11、C++ 14、およびC++ 17標準は、C++ 98と本質的に同じと言っています。

共通の拡張子

従来、Unixシステムは3番目のバリアントをサポートしています。

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

3番目の引数は、文字列へのポインターのヌル終了リストです。各ポインターは、名前、等号、および値(空の場合もある)を持つ環境変数です。これを使用しない場合でも、「_extern char **environ;_」経由で環境にアクセスできます。長い間、それを宣言するヘッダーはありませんでしたが、POSIX 2008標準では、_<unistd.h>_で宣言する必要があります。

これは、付録Jに記載されている共通の拡張機能としてC標準で認識されています。

J.5.1環境引数

¶1ホストされた環境では、メイン関数は3番目の引数_char *envp[]_を受け取ります。これは、charへのポインターのNULLで終わる配列を指します。プログラムのこの実行のための環境(5.1.2.2.1)。

Microsoft C

Microsoft VS 201 コンパイラは興味深いです。ウェブサイトは言う:

Mainの宣言構文は

_ int main();
_

または、オプションで、

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

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

void main()を含むプログラムが終了したときに何が起こるか(親またはo/sにどの終了コードが返されるか)が明確ではありません。MSWebサイトもサイレントです。

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

Microsoftのページには、他の代替手段もリストされています— wmain()はワイド文字列などを取ります。

Microsoft VS 2005バージョンの このページ は、代替としてvoid main()をリストしません。 versions はMicrosoft VS 2008以降のものです。

int main()int main(void)と同じですか?

詳細な分析については、 CおよびC++でmain()を返す必要があるもの に対する回答の最後を参照してください。 (この質問はC++を参照しているとは思わなかったにもかかわらず、C++を参照していると考えたことがあります。C++では、int main()int main(void)int main()は慣用的なC++です。)

Cでは、2つの表記に違いがありますが、難解な場合にのみ気づきます。具体的には、独自のコードからmain()関数を呼び出すと違いがあります。これはCで許可されており、C++で許可されていません。

int main()表記はmain()のプロトタイプを提供しませんが、それは再帰的に呼び出す場合にのみ重要です。 int main()を使用すると、後で(同じ関数または別の関数で)int rc = main("absolute", "twaddle", 2):を記述できますが、正式にはコンパイラはコードのコンパイルを拒否する程度に文句を言うべきではありませんがそれについて合法的に文句を言う(警告する)ことがあります(GCCで_-Werror_を使用すると、警告がエラーに変換されます)。 int main(void)を使用すると、その後のmain()の呼び出しでエラーが発生します。関数は引数をとらないと言いましたが、3つを提供しようとしました。もちろん、宣言または定義する前にmain()を合法的に呼び出すことはできません(まだC90セマンティクスを使用している場合を除く)—実装はmain()のプロトタイプを宣言しません。注意:C11標準は、異なる例でint main()int main(void)の両方を示しています—両者には微妙な違いはありますが、Cでは有効です。

16

POSIXはexecve()をサポートしています。

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

追加された引数は環境、つまりNAME = VALUE形式の文字列の配列です。

8
unwind

http://en.wikipedia.org/wiki/Main_function_(programming)#C_and_C.2B.2B

通常のint main(int argc, char *argv[])およびPOSIX int main(int argc, char **argv, char **envp)に加えて、Mac OS Xでは

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

もちろん、Mac専用です。

Windowsには

int wmain(int argc, wchar_t* argv[], wchar_t* envp[]);

unicode(実際には、ワイド文字)バリアントとして。もちろん、WinMainもあります。

8
kennytm
_int main(void)
_

一部のOS(Windowsなど)でも同様に有効です。

_int main(int argc, char **argv, char **envp)
_

ここで、envpは環境を提供します。それ以外の場合はgetenv()からアクセスできます

3
flashnik