OS環境下のCプログラムでは
int main(void)
{
printf("hello,world\n");
return 0;
}
のように必ず関数の戻り値の型を int にして、return で値を返すように書きます。
main()は真っ先に実行される関数であり、入門書においても真っ先にでてくる存在ですが、入門書では、初心者に最初に余計なことを考えさせないためや入力の手間を省くため、適当に端折った表現で記述されることが多いです。たとえば
main()
{
printf("hello, world\n");
}
void main()
{
printf("hello, world\n");
}
void main(void)
{
printf("hello, world\n");
}
int main(void)
{
printf("hello, world\n");
}
などなど。もちろん後でフォローをいれて修正するものもありますが、最後まで貫きとおすものもあります。
4つの例のうち void main(void) 以外は、コンパイラの型チェックによって警告メッセージが出てしまうという意味での問題があるのですが……エラーだけでなく警告となる問題点も修正する、という習慣をつけたほうがよい現状において、いくら本と同じに入力していても消えない警告があると悩む人は悩みますし、あるいは、警告メッセージを気にしない気づけない人になるのを助長するように思います……たとえそのような文法的に問題のなさそうな
void main(void) であっても実用のプログラムでは問題になります。
ISO-C/ANSI-Cでは 少なくとも OS環境下のプログラムにおける
main の定義は
int main(void)
または
int main(int argc, char *argv[])
(あるいはかきかたによって int main(int argc, char **argv) )
の2種類と決まっています。
どちらの場合でも main は int の値を返す関数と決まっているということです。
このint を返す、というのが大事なことで、このmainのreturn
から返される値はプログラム終了時にOSに渡されるエラーコードになり、少なくとも
0ならば正常終了
0以外ならば異常終了
ということがきまっており、大概の場合はC標準関数の
exit関数の引数の値と同じものが指定できます(exit関数は、プログラムを終了させる関数で、その引数はOSに返す値となっています)。
ちょっと混乱している方がいるかもしれませんが、
Cプログラムを書く人間にとって main 関数は特殊な存在だけど、Cコンパイラにとっては他の関数と同様の存在でしかない
ということです。プログラマが void main(void)
と書いたところで、void の場合は自動的に OS
に 0を返す、というような処理をやってくれないわけです。
ちょっとややこしい話になってきますが、C言語のプログラムは普通、OSに起動されたとき、ホントのしょっぱなに
main() がいきなり実行されるのでなく、スタートアップルーチンというアセンブラなりCなりで書かれたルーチンがあり(ユーザが直接見れないという意味ではライブラリ関数とかと同様なもの)、そのルーチンがOSから真っ先に呼ばれOSからの情報をを元に初期化等を行いC言語での都合にあわせたあと、main()関数を呼び出しているわけです。
そしてmain() がint値を返すのを期待し、その返された値を
OS に返す値に変換して(大抵はそのままだけど)返し、終了するわけです。
そのルーチンは、ユーザが main をどんな宣言にしようと変化するわけでなく、int値が返されるのを前提にしているので、もし
void main(void) や return値のない int main()
の場合、不定な値(何かのごみ)を返すため……
voidだからって勝手に0を戻り値とする、というような仕組みもありません
…… 結果、OSにむちゃくちゃな値が返されることになります。
ということで、実用的なプログラムでは、OSにきちっとエラーコードを返す必要があるので/返したほうが好ましいので、仕様どおりに main を書いたほうがよいです。
ただOSに値を返すということだけを言えばCが標準化される前の時代の方法を用いて
#include <stdio.h>
#include <stdlib.h>
void main()
{
printf("hello,world\n");
exit(0);
}
のように exit() を用いてばvoid main() でも正常終了することはできます。が、さして手間が減るわけでなく(かえって手間かもしれない)、わざわざANSI-Cの規定外にする必要もないでしょうから
int main にされたほうがよいでしょう。
と、書きましたが、あくまでエラーコードを返すべき、エラーコードを受け取るOSが存在する環境での話で、もちろん組み込み系などとなってくると別の話です。
で、問題は MS-DOS(MS-WindowsでのDOS窓の場合)で、OS(正確にはShellであるcommand.com)自体がエラーコードを無視する傾向があり、実際のところエラー値を見る
bat ファイルを書くか、makeプログラムのようなものを使うのでうのでない限り、OSに返される値が正常でなくても対して困らない人も多いのが現状だったりもします。
(だから void main と書いても平気なのね)
が、makeやshellスクリプトに記述して問題があるようなコマンドラインツールは利用価値が半減するといえるでしょう。
またwindowアプリケーションの場合、main()ではなくWinMain()等の自前の規則でかつヘッダに定義してエラーチェックしてますしOSが異常終了時のメッセージを出すので無作法を許さないようになっているモノもあります。