第17回
コマンドライン引数と終了コード~main関数の基本事項

終了コードを返す

リスト1がyesno.cのソースです。コマンドライン引数については少し難しくなるので、順序を逆にして先に終了コードから説明していきましょう。

main関数が値を返す

リスト1:プロンプトを表示して'y'または'n'の入力を受け付ける~(yesno.c)
/* --------------------------------------------------------
   yesno.c -- メッセージを表示してY/Nの入力を待つ。
              [Y]なら0、[N]なら1を終了コードとして返す。
   ------------------------------------------------------- */

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{
  char strMessage[255] = "Are you ready?";
  int chAnswer;

  if (argc > 1)
    strcpy(strMessage, argv[1]);

  strcat(strMessage, " <y/n>");

  puts(strMessage);
  chAnswer = getchar();
  if (chAnswer == 'y' || chAnswer == 'Y')
    return(0);
  else
    return(1);
}

main関数の最後の}に到達すると、プログラムは終了します。もちろん、ただ単純に終了するわけではなく、後処理が行われます。この後処理の中でも重要な働きが「終了コードを返す」処理です。

終了コードとは、main関数が終了したとき=プログラム終了したときにreturnによってプログラムが呼び出し元に返す値です。
return (<値>);

returnで返す<値>はint型の整数です。これは、main関数の先頭で定義されているmain関数の型と同じです。
int main(int argc, char *argv[])

yesno.cでは、
(a)getchar関数でキーボードから受け取った1文字を変数chAnswerに保存し
(b)それが'y'または'Y'だったら0を
(c)それ以外の場合には1を
返すようにしています。

以下のソースの(a)(b)(c)と照らし合わせてください。
chAnswer = getchar(); ---- (a)
if (chAnswer == 'y' || chAnswer == 'Y')
  return(0); -------- (b)
else
  return(1); -------- (c)

main関数も呼び出される

Cプログラムの中心(開始~終了までの処理)はmain関数に統合されていると言われますが、それはあくまでプログラマーから見えるソースコードレベルでの話です。実際には、Cのスタートアップ・ルーチンが最初に実行され、その中でmain関数が呼び出されます。

Cのプログラムはmain関数を含む様々な関数がコンパイルされた後、生成されたオブジェクト・ファイルがリンカによって結合されてできあがりますが、そのときスタートアップ・ルーチンも結合されます。

OSが最初に実行するのはスタートアップ・ルーチンで、その中で様々な初期化が行われた後にmain関数が呼び出されるのです。従って、main関数内でreturnを使って返された値はスタートアップ・ルーチンが受け取り、最終的にプログラムを呼び出したプログラム──一般的にはシェル・プログラム ※1 ──に返されます。

OSの中枢部分であるカーネルとユーザーとを仲介し、OSのユーザーインターフェイスを確立するプログラム。コマンドの受け取り、プログラムの実行、自動処理(バッチ処理、シェルスクリプトなど)の実行などを行います。MS-DOSではCOMMAND.COM、UNIX系OSではsh、bashなど数種類あります

自動処理で利用される

プログラムを呼び出したシェルはプログラムの返す値を終了コードとして受け取り、MS-DOSのバッチファイルやUNIX系OSのシェルスクリプトの中で条件判断と分岐の構造により、処理の流れを切り替えるために用いられます。

リスト1では、キーボードから入力された1文字をifで判断し、それが"y"または"Y"ならreturnで0を返し、それ以外ならreturnで1を返しています。この値を、例えばMS-DOSならシェル・プログラムのCOMMAND.COMが受け取って変数ERRORLEVELに保存し、バッチファイルの中で利用します。

終了コードは、単純にプログラムをプロンプトに対するコマンドラインから実行した場合には利用されません。シェルスクリプトやバッチファイルなど、次々とプログラムを実行する中で、処理の流れを切り替える目的で利用されます。


実行環境によって異なる

終了コードとして返す値に決まりがある訳ではありませんが、通常は正常終了の時には0を、エラーなら0以外を返すことになっています。単純にエラーで終了したことだけを知らせる場合は-1がよく使われます。エラーの様々な状態を知らせたい場合には、1、2、3などint型で扱える範囲の整数を、終了時の状況に応じて返すようにします。

なお、main関数の返す値はint型となっていますが、MS-DOSのバッチファイルでは終了コードを受け取る変数ERRORLEVELが8ビットなので、0~255までの整数しか扱えません。そのため、エラー時に返す値を-1としても255としても同じ結果となります ※2

終了コードに関しては、プログラムを実行するOS(で実行するシェルプログラム)によって仕様が異なるため、値の設定に注意する必要があります。

8ビットの整数はsigned char(符号付き)なら-1、unsigned char(符号なし)なら255が16進数で最大値のoxff(FFh)となるため、どちらの場合もバッチファイル内ではERRORLEVELが255となります。但しこれは、DOSのバージョンによっても違いがあるようです