[迷信] void main(void)

これは最も頻繁に目にする誤りであり、多くの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 であろうと、あるいは関数名が wmainWinMain であろうと、移植性はありませんが、一応規格合致ということになります。

ただし、この仕様はあくまでも 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() のような記述があったとしても、その書籍の有用性とは直接関係ないので、大目に見てあげてください。

gccで -ansiと-pedanticをつけてコンパイル

gccで
-ansiと-pedanticをつけてコンパイルしても規格外と判定されますね

コメントありがとうございます

バージョン等にもよるのでしょうが、手元のGCC 4.2.1では、何もオプションを付けなくても-pedanticを付けた場合と同様の警告が出ます。
警告が出ないのは(警告を抑止するオプション以外では)-ffreestandingオプションを付けたときぐらいでしょうか。

IE6 での表示異常を修正しました。

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

このエントリーを含むはてなブックマーク