C99 では、void main が、プログラムの入り口として認められたらしいのですが、どう解釈すれば良いでしょうか?
http://q.hatena.ne.jp/1349682459#ac48153
で、教えてもらった
http://www.kijineko.co.jp/tech/superstitions/void-main.html
で、規格が引用されている部分を読むと、
「C99 に対応している処理系であれば、戻り値が int ではなくても、main という関数を開始処理として呼び出さなくてはいけない」
と書いているように思うのですが。
コーディングスタイルとして、どれが良い、というような回答は、あまり期待してません。
昔の規格に慣れ親しんだ身としては、int main って勝手に指は動きますし、void main を擁護する事情も持ち合わせてはいませんので。
引用の引用で恐縮ですが、以下の件です。
>http://www.kijineko.co.jp/tech/superstitions/void-main.html>
5.1.2.2.1 プログラム開始処理 プログラム開始処理において呼び出される関数の名前は,main とする。処理系は,この関数に対して関数原型を宣言しない。この関数は,次の4種類の方法のいずれかで定義しなければならない。
- 返却値の型 int をもち仮引数をもたない関数
int main(void) { /* ... */ }
- 二つの仮引数をもつ関数(仮引数は,これらが宣言された関数に対して局所的であるため,どのような名前を使用してもよいが,ここでは argc 及び argv とする。)
int main(int argc, char * argv[]) { /* ... */ }
- 上に掲げた二つの方法のいずれかと等価な方法
- 上に掲げた三つの方法のいずれでもない処理系定義の方法
<<
.1.2.1 フリースタンディング環境 フリースタンディング環境では,オペレーティングシステムのいかなる支援もなしに C プログラムの実行を行う。プログラム開始時に呼び出される関数の名前及び型は,処理系定義とする。
(中略)
5.1.2.2.1 プログラム開始処理 プログラム開始処理において呼び出される関数の名前は,main とする。処理系は,この関数に対して関数原型を宣言しない。この関数は,次の4種類の方法のいずれかで定義しなければならない。
- 返却値の型 int をもち仮引数をもたない関数
int main(void) { /* ... */ }
- 二つの仮引数をもつ関数(仮引数は,これらが宣言された関数に対して局所的であるため,どのような名前を使用してもよいが,ここでは argc 及び argv とする。)
int main(int argc, char * argv[]) { /* ... */ }
- 上に掲げた二つの方法のいずれかと等価な方法
- 上に掲げた三つの方法のいずれでもない処理系定義の方法
「処理系定義の方法」を逆さまに読んでいるんじゃないでしょうか。「int main(int, char **) 以外の形で main() を呼び出す処理系実装がC99を名乗ることが許される」という意味であって、「ある特定のC99処理系に好き勝手な main() を与えた際に正しく動作する」という意味ではないはずです。
むしろここで問題になっているのは、main()については「処理系は,この関数に対して関数原型を宣言しない」(原文: The implementation declares no prototype for this function.) の方で、つまり見るからに互換性のありそうにないmain()が与えられた場合でも、処理系はエラーではじくことができないのです。この意味では void main() あるいはその他一切の奇怪な main() がコンパイルエラーにならないことはたぶん保証されています。ただしそれが必ず正常動作することまでは意味していないはずです。
たぶんわかってるだろうとは思いますがmain()の戻値についての規定は 5.1.2.2.3 で、「戻値の型が int 互換であれば return a は exit(a) と(ほぼ)等価である」べきこと、「} に達した場合は return 0; と等価である」べきこと、「型が int 互換でない場合は結果が不定である」こと、とあります。また引数の側についても最初の二つについては 5.1.2.2.1 の2段落目で、宣言された場合に引き渡されるべき内容が規定されているので、実際には「処理系定義の方法」といっても無視可能な第三引数以降を追加するだけでないと規格から外れる気がします。
「逆さまに読んでいる」がよく分からなくて、しばらく考えてたんですけど、
「次の4種類の方法の *いずれか* で定義しなければならない。」を、
「4種類の方法の *全て* で」と誤解しているんだろう、ということですね。
極端な話、start up ルーチンが、void main(void) なエントリーしか呼び出せなくても、C99 処理系を名乗れる、と。
処理系はプロトタイプ宣言は定義しないから、コンパイルは通るはずだよね、ってことですか。
>「次の4種類の方法のいずれかで定義しなければならない。」
「定義しなければならない。」とありますが、定義するのはmain関数ですね。
では誰が定義するのかといえば、処理系ではなくプログラマですよね。
つまり、プログラマは
ということになると思います。
したがって処理系は
ということになるかと思います。
さて、ここで4つ目を選んだプログラマが行える定義はなにかというと、
「なんでもいい」
ではなく
「処理系定義の方法」
です。
でどうなるかといえば、
処理系依存の方法でコーディングしてもC99準拠を名乗れるけれど、
処理系依存は処理系依存なので、C99準拠だけど処理系によっては正常動作しない可能性のあるコードになる、
ということになるかと。
ISO/IEC 9899:1999 の原文。
>http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf>
5.1.2.2.1 Program startup
The function called at program startup is named main. The implementation declares no
prototype for this function. It shall be defined with a return type of int and with no
parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be
used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;9) or in some other implementation-defined manner.
9) Thus, int can be replaced by a typedef name defined as int, or the type of argv can be written as
char ** argv, and so on.
<<
JIS とあまり変わらないですね(当たり前)。
処理系は独自の呼び出し方を用意して良いし、それを使ったとしても C99 準拠を名乗れる、というだけで、void main が許されたというのは、ちょっと誤解を招く表現、ということになるのかな。
いや、許されてはいるのか。
規格としては認めるけど、処理系依存だからね、と明記されたと取るべきか...
質問に書いたリンク先の内容を貼って、何がしたいの?
2012/10/13 13:43:30