main関数がargcとargvの2つの仮引数を受け取る場合、argv[0]がプログラム名を表す文字列を指すというのは入門書にも載っています。しかし、常にそうかというと、実はそうではありません。今回はフリースタンディング環境の話は除外して、ホスト環境の話に限って、この部分の事実関係がどうなっているかをご紹介します。
argv[0]がプログラム名にならないケースは、大きく分けて2つあります。ひとつは、そのそもmain関数にプログラム名が渡されないケースがある場合で、もうひとつは、ユーザープログラムからmain関数を呼び出した場合です。
まずは、そもそもmain関数にプログラム名が渡されないケースについて見ていきます。JIS X3010:2003の5.1.2.2.1 プログラム開始処理から引用すると……
二つの仮引数を定義する場合,関数mainの仮引数は,次の制約に従わなければならない。
– argcの値は,非負でなければならない。
– argv[argc]は,空ポインタでなければならない。
(中略)
– argcの値が正の場合,argv[0]が指す文字列は,プログラム名(program name)を表す。ホスト環境からプログラム名を得ることができない場合,argv[0][0]は,ナル文字でなければならない。
上記はC言語の規格ですが、C++の規格であるJIS X3014:2003でも(表現は違いますが)同様のことが規定されています。これからも分かるように,argcは非負でなければならないので0でもいいことになります。argcが0の場合にはargv[0](すなわちargv[argc])は空ポインタ(=NULL)ですので,プログラム名ではないことになります。
このような処理系は実在します。また,argc > 0であっても,プログラム名が得られない場合はargv[0]が””を指すことになります(このようになる具体的な処理系は知りませんが……)。
次に,ユーザープログラムからmain関数を呼び出す場合です。これはC言語では可能ですが、C++ではmain関数を直接呼び出すことも、関数へのポインタを介して間接的に呼び出すことも原則としてできません。ですので、以下はC言語に限った話になります。
ユーザープログラムからmain関数を呼び出す場合、それこそ実引数にどんなものを渡すかはプログラムの作り方次第になります。argcに負の値を渡すことも、argvに空ポインタを渡すこともできてしまいます。ですので、argv[0]がプログラム名になるかどうかも、完全にユーザープログラムの作り方次第になるわけです。
若干余談にはなりますが、Visual C++ではWinMain関数やwWinMain関数からmain関数を呼び出せるようです。CygwinやMinGWではmain関数からWinMain関数を呼び出しているので移植性が必要な場合は注意が必要です。