【void main @C言語】 


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 を擁護する事情も持ち合わせてはいませんので。

回答の条件
  • 1人5回まで
  • 登録:
  • 終了:2012/10/20 10:27:49
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。
id:a-kuma3

引用の引用で恐縮ですが、以下の件です。

>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[]) { /* ... */ }

- 上に掲げた二つの方法のいずれかと等価な方法

- 上に掲げた三つの方法のいずれでもない処理系定義の方法

JIS X3010:2003より引用

<<

回答2件)

id:sanada33 No.1

回答回数293ベストアンサー獲得回数3

.1.2.1 フリースタンディング環境 フリースタンディング環境では,オペレーティングシステムのいかなる支援もなしに C プログラムの実行を行う。プログラム開始時に呼び出される関数の名前及び型は,処理系定義とする。


(中略)

5.1.2.2.1 プログラム開始処理 プログラム開始処理において呼び出される関数の名前は,main とする。処理系は,この関数に対して関数原型を宣言しない。この関数は,次の4種類の方法のいずれかで定義しなければならない。
- 返却値の型 int をもち仮引数をもたない関数
      int main(void) { /* ... */ }
- 二つの仮引数をもつ関数(仮引数は,これらが宣言された関数に対して局所的であるため,どのような名前を使用してもよいが,ここでは argc 及び argv とする。)
      int main(int argc, char * argv[]) { /* ... */ }
- 上に掲げた二つの方法のいずれかと等価な方法
- 上に掲げた三つの方法のいずれでもない処理系定義の方法

id:a-kuma3

質問に書いたリンク先の内容を貼って、何がしたいの?

2012/10/13 13:43:30
id:vow No.2

回答回数21ベストアンサー獲得回数9

ポイント100pt

「処理系定義の方法」を逆さまに読んでいるんじゃないでしょうか。「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段落目で、宣言された場合に引き渡されるべき内容が規定されているので、実際には「処理系定義の方法」といっても無視可能な第三引数以降を追加するだけでないと規格から外れる気がします。

id:a-kuma3

「逆さまに読んでいる」がよく分からなくて、しばらく考えてたんですけど、
「次の4種類の方法の *いずれか* で定義しなければならない。」を、
「4種類の方法の *全て* で」と誤解しているんだろう、ということですね。

極端な話、start up ルーチンが、void main(void) なエントリーしか呼び出せなくても、C99 処理系を名乗れる、と。
処理系はプロトタイプ宣言は定義しないから、コンパイルは通るはずだよね、ってことですか。

2012/10/13 17:43:09
id:TransFreeBSD

>「次の4種類の方法のいずれかで定義しなければならない。」
「定義しなければならない。」とありますが、定義するのはmain関数ですね。
では誰が定義するのかといえば、処理系ではなくプログラマですよね。

つまり、プログラマは

  • 4つの方法以外では定義してはならない。
  • 4つの方法のどれで定義しても良い。

ということになると思います。
したがって処理系は

  • 4つの方法以外で正常動作する必要はない。
  • 4つの方法ではればどれでも正常に動作するようにしなければならない。

ということになるかと思います。

さて、ここで4つ目を選んだプログラマが行える定義はなにかというと、
「なんでもいい」
ではなく
「処理系定義の方法」
です。

でどうなるかといえば、
処理系依存の方法でコーディングしてもC99準拠を名乗れるけれど、
処理系依存は処理系依存なので、C99準拠だけど処理系によっては正常動作しない可能性のあるコードになる、
ということになるかと。

2012/10/14 23:49:40
id:a-kuma3

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 が許されたというのは、ちょっと誤解を招く表現、ということになるのかな。

いや、許されてはいるのか。

規格としては認めるけど、処理系依存だからね、と明記されたと取るべきか...

  • id:pascal7
    OS側にエラー値を扱う機構があれば
    int main()に意味がありますし。

    OSの側にエラー値を扱う機能がなければ
    値を返す意味がないではないですか。

    そのようなOSの上で動作する処理や
    全く終了しない処理(組み込みとか)
    他の言語で起動するだけで返値を扱わない言語から呼ばれる場合
    void main()の方が適当ではないですか。
  • id:vow
    処理系の実装方針としての話であれば全くその通りです。

    が、それはC99規格上の main() の規定とは無関係です。つまり、組み込み云々上のC99実装において、C99規格上の main() がどうこうと、議論すること自体が不適切です。なんとなれば、main() の話はあくまで Hosted environment、おおざっぱに言えばシェルからコマンドライン経由で駆動される慣行に沿った環境を、処理系が提供する場合の話だからです。そうでない場合については Freestanding environment として別の条項があり、そもそも main() についての規定自体が適用されません。

    規格準拠云々とは関係なくもう一つ別の論点として言うならば、C99的Hosted環境と互換性がないスタートアップ規約に、わざわざC99で定義された名前であるところの main() と命名する処理系実装上の選択は、どちらかと言えば嫌がらせに近いと思います。なんで互換性の無いものにわざわざ同じ名前を付けるんだという話です。

    ただし、呼び出し規約的に int (*f)() と void (*f)() には(不定な戻値に目をつむるならば)たいてい互換性があるので、*処理系の側が* 「void main() *でも* 良い」という仕様を採ることは可能ですし、それは規格の範囲内に収まります。現に実在する実装の大半は(それを実装仕様として書いているかどうかはともかく)この状態にあるので、とりあえず void main() でも暴走したりはしないわけです。

    いずれにせよ、「処理系依存でないC99準拠」のコードである限り、main() は int main(void) あるいは int main(int, char**) のいずれかに互換でなければならない、という点は覆りません。よって、仮にmain()の戻値の行先が実在しないことが確実な文脈であったとしても、プログラマが void main() と書くことが妥当であるか否かは、そのコードが処理系依存になることが妥当であるか否かに依ります。

    ・・・という解釈で問題ないはずだけど、さていったいどっちの方が迷信なんでしょうね:-)
  • id:a-kuma3
    ぼくが質問で引き合いに出した「きじねこ」の「C/C++迷信集」は、ざっと見た感じ、記事のタイトルが迷信として書かれているようなのですが、この void main (void) というタイトルは、よく分かりません。

    ・void main(void) は、正しい(という迷信)
    ・void main(void) は、間違っている(という迷信)
    ・void main(void) は、昔は正しくなかったが、今は正しい(という迷信)
    ・void main(void) は、C99 では規格として認められた(という迷信)

      (?_?)


    原文で言えば、処理系ではなく、コードの側として、四つの方法が OR で結合されているので、四つとも処理系は受け入れなさい、というように読めちゃいますが、"some other implementation-defined manner" には、「もし、処理系が先の三つ以外の方法を用意しているならば」というフレーズを補って読むべきなのでしょうね。

この質問への反応(ブックマークコメント)

トラックバック

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません