これは最も頻繁に目にする誤りであり、多くのC/C++の間に根強い迷信として広まっています。もしかすると、タイトルを見ただけでは問題点が理解できない方さえおられるかもしれません。そこで、今回はいきなり標準規格からの引用から始めたいと思います。
5.1.2.1 フリースタンディング環境 フリースタンディング環境では,オペレーティングシステムのいかなる支援もなしに C プログラムの実行を行う。プログラム開始時に呼び出される関数の名前及び型は,処理系定義とする。
(中略)
5.1.2.2.1 プログラム開始処理 プログラム開始処理において呼び出される関数の名前は,main とする。処理系は,この関数に対して関数原型を宣言しない。この関数は,次の4種類の方法のいずれかで定義しなければならない。
- 返却値の型 int をもち仮引数をもたない関数
int main(void) { /* ... */ }
- 二つの仮引数をもつ関数(仮引数は,これらが宣言された関数に対して局所的であるため,どのような名前を使用してもよいが,ここでは argc 及び argv とする。)
int main(int argc, char * argv[]) { /* ... */ }
- 上に掲げた二つの方法のいずれかと等価な方法
- 上に掲げた三つの方法のいずれでもない処理系定義の方法JIS X3010:2003より引用
上記は標準Cに関するものです。続いて標準C++の仕様を見てみましょう。
3.6.1 関数 main プログラムには,大域的な関数 main が含まれていなければならない。この関数から,プログラムの実行が始まる。自立処理系でのプログラムに関数 main を定義する必要があるかどうかは,処理系定義とする。
参考 自立処理系においては,プログラムの開始及び終了は,処理系定義とする。開始では,少なくとも,静的記憶域期間をもつ名前空間有効範囲のオブジェクトに対するコンストラクタを実行する。終了では,少なくとも,静的記憶域期間をもつオブジェクトに対するデストラクタを実行する。処理系は,関数 main をあらかじめ定義しておいてはならない。その返却値の型は,int とする。これを除いて,関数 main の型は,処理系定義とする。処理系は,次に示すどちらの形での関数 main の定義も受理できなければならない。
int main(void) { /* ... */ }
int main(int argc, char* argv[]) { /* ... */ }JIS X3014:2003より引用
かなり長い引用になってしまいましたが、お分かりいただけたでしょうか。なお、C++でいうところの「自立処理系」というのは、フリースタンディング環境の処理系のことです。ちなみに、ホスト環境の処理系のことは「依存処理系」といいます。
フリースタンディング環境の場合は、プログラム開始時に呼び出される関数は名前も型も処理系定義ですので、ここでは特に取り上げません。以下はホスト環境に限っての話と考えてください。
標準Cでは、4番目として、処理系定義の"何でもあり"の方法が認められています。したがって、main の返却値の型が void であろうと、あるいは関数名が 移植性はありませんが、一応規格合致ということになります。
wmain や WinMain であろうと、
ただし、この仕様はあくまでも JIS X3010:2003 すなわち ISO/IEC 9899:1999(通称 C99)のものであり、旧規格では4番目の方法は認められていません。したがって、C99 に対応していない処理系では、main の返却値の型はやはり int でなければならないのです。
一方、標準C++では、main の返却値の型は int でなければならないことが明記されていますので、そうでない場合は規格合致処理系ではなくなります(つまり、非標準処理系ということになります)。もっとも、現存するC++処理系の多くは、完全に規格合致ではありませんので、五十歩百歩だという見方もあります。
ところで、C/C++の入門書を始めとする言語そのものの解説書や、学校の教材では、わざわざ特定の処理系でしか使うことができない void main() という記述を用いる必然性はどこにもありません。入門書などを選ぶ際には、main の返却値の型がどうなっているかをまずは調べるとよいとよく言われます。もし、void になっているようであれば、C/C++の規格を理解していない著者が書いたものですので、他の記述もあまりあてにはなりません。
なお、C/C++の言語そのものの解説ではない書籍、例えば圧縮アルゴリズムに関する書籍に void main() のような記述があったとしても、その書籍の有用性とは直接関係ないので、大目に見てあげてください。
トラックバック
ブックナビゲーション
- 技術情報
- Boost C++ Libraries メモ
- C++と組込み環境
- C++サンプル集
- C++テンプレート集
- C++プログラマのためのC言語入門
- C/C++迷信集
- [迷信] 'A'~'Z' の値は連続している
- [迷信] 0xe-0xe はゼロ
- [迷信] 1 バイトは 8 ビット
- [迷信] 2の累乗による割り算と右シフトは等価
- [迷信] FILE 型は構造体
- [迷信] abs は常に非負の値を返す
- [迷信] argv[0] はプログラム名
- [迷信] char 型は符号付き
- [迷信] double の出力書式は "%lf"
- [迷信] fflush で入力バッファをクリア
- [迷信] free でメモリを開放する
- [迷信] free に NULL を渡すとクラッシュする
- [迷信] gets は単純に fgets に置き換えられる
- [迷信] isalpha 関数の引数は char 型
- [迷信] new に失敗すると NULL が返る。
- [迷信] scanf ではバッファオーバーランを防げない
- [迷信] scanf でキーボードから入力
- [迷信] setjmp マクロの返却値は変数に代入できる
- [迷信] sizeof は定数式
- [迷信] void main(void)
- [迷信] とりあえず memset で初期化
- [迷信] アルゴリズム関数内で関数オブジェクトはコピーされない
- [迷信] オブジェクトの動的生成に失敗するとメモリリークする
- [迷信] コンストラクタから例外を送出してはならない
- [迷信] コンストラクタで自身をゼロクリア
- [迷信] コンパイラはプログラマの心を察してくれる
- [迷信] コンパイルエラーが出るのでアクセス指定子を修正
- [迷信] ソースコード中の即値を全廃せよ
- [迷信] ソースファイルの末尾に }
- [迷信] データ列のソートには qsort 関数を使うべし
- [迷信] プログラムは必ず main から始まる
- [迷信] 一重引用符の中には一文字しか書けない
- [迷信] 今どき int が 16 ビットの処理系なんて無い
- [迷信] 入力データ格納用配列のサイズは BUFSIZ
- [迷信] 割付けたメモリはプログラマが自分で解放しなければならない
- [迷信] 実数型とは浮動小数点型のことである
- [迷信] 引用符で囲んだヘッダ名はカレントディレクトリから探索する
- [迷信] 文字列から整数への変換には atoi
- [迷信] 構造体のタグ名は下線で始める
- [迷信] 構造体はクラスではない
- [迷信] 識別子に使える文字は英数字と下線のみ
- [迷信] 非局所オブジェクトは外部結合
- C言語再入門
- C言語徹底入門
- Drupal メモ
- TOPPERS 情報
- ライブラリ開発入門
- 分割コンパイルをきわめる
- 擬似プロセッサを作る
- 車輪の再発明
- 過去の情報


IE6 での表示異常を修正しました。
インターネットエクスプローラ6で見ると表示がおかしかったので修正しました。