プログラム環境
main()
は関数であることがわかった。プログラムの実行はmain()
から始まり、そこから他の関数に分岐する。これまで使用してきたmain()
の定義は、次の通りである。
この定義によると、main()
は引数を受け取らず、値を返さない。実際には、ほとんどのシステムでは、すべてのプログラムは終了時にその環境に値を返す。この値は、終了ステータスまたはリターンコードと呼ばれる。このため、main()
の戻り値の型をvoid
と指定することは可能だが、実際にはオペレーティングシステムまたは起動環境に値が返される。
main()
の戻り値
プログラムは、常に特定の環境にあるエンティティによって起動される。プログラムを起動するエンティティは、ユーザーがプログラムの名前を入力してEnterキーを押すシェル、プログラマが[実行]ボタンをクリックする開発環境などである。
Dや他のいくつかのプログラミング言語では、プログラムはmain()
の戻り値によって、その終了状態をその環境に伝える。
リターンコードの正確な意味は、アプリケーションやシステムによって異なる。ほとんどすべてのシステムでは、リターン値が0は正常終了を意味し、その他の値は一般的に何らかのエラーを意味する。ただし、これには例外がある。例えば、OpenVMSでは、偶数値はエラーを意味し、奇数値は成功を意味する。それでも、ほとんどのシステムでは、[0, 125]の範囲の値は安全に使用でき、1から125までの値は、そのプログラムに固有の意味を持つ。
例えば、ディレクトリの内容を表示するために使用される一般的なUnixプログラムls
は、成功すると0、軽微なエラーが発生すると1、重大なエラーが発生すると2を返す。
多くの環境では、ターミナルで最後に実行されたプログラムの戻り値は、$?
環境変数で確認できる。例えば、ls
に存在しないファイルの一覧を表示するように指示すると、その戻り値が0以外であることが、以下のように$?
で確認できる。
注釈:以下のコマンドラインでのやり取りでは、#
で始まる行は、ユーザーが入力した行を表している。同じコマンドを試してみたい場合は、#
以外の文字を入力する。また、以下のコマンドはdeneme
という名前のプログラムを実行している。この名前を、テストするプログラムの名前に置き換える。
さらに、以下の例はLinuxターミナルでの対話操作を示しているが、他のオペレーティングシステムのターミナルでも同様だが、まったく同じとは限らない。
main()
は常に値を返す
これまで作成したプログラムの中には、タスクを続行できない場合に例外をスローするものがあった。これまで見てきたように、例外がスローされると、プログラムは"object.Exception
"というエラーメッセージで終了する。
その場合、main()
がvoid
を返すように定義されていても、プログラムの環境に非ゼロのステータスコードが自動的に返される。次の例外で終了するシンプルなプログラムで、この動作を確認しよう。
戻り値の型はvoid
と指定されているが、戻り値は0以外だ。
同様に、正常に終了するvoid main()
関数も、自動的に0を戻り値として返す。これを、正常に終了する次のプログラムで見てみよう。
プログラムは0を返す:
戻り値の指定
特定の戻りコードを選択するには、他の関数と同じように、main()
から値を返す。戻り値の型はint
と指定し、値はreturn
文で返す必要がある。
入力した数値が有効範囲内にある場合、プログラムの戻り値は0になる。
数値が有効範囲外の場合、プログラムの戻り値は111になる。
上記のプログラムでは、値111は任意だが、通常は1が失敗コードとして適している。
標準エラーストリームstderr
上記のプログラムは、stderr
ストリームを使用している。このストリームは、標準ストリームの3番目のもので、エラーメッセージの書き込みに使用される:
stdin
: 標準入力ストリームstdout
: 標準出力ストリームstderr
: 標準エラーストリーム
プログラムをターミナルで実行すると、通常、stdout
とstderr
に書き込まれるメッセージはどちらもターミナルウィンドウに表示される。必要に応じて、これらの出力を個別にリダイレクトすることも可能だ。このテーマは、この章の焦点外であり、シェルプログラムごとに詳細が異なる場合がある。
パラメーターmain()
プログラムは、それを起動した環境からパラメータを受け取るのが一般的だ。例えば、先ほど、ls
にファイル名をコマンドラインオプションとして渡した。次の行には2つのコマンドラインオプションがある。
コマンドラインパラメーターのセットとその意味は、プログラムによって完全に定義される。すべてのプログラムは、各パラメーターの意味を含む使用方法を文書化している。
Dプログラムを開始するときに使用される引数は、string
のスライスとしてそのプログラムのmain()
に渡される。main()
を、string[]
型のパラメータを受け取るものとして定義すれば、プログラムの引数にアクセスできる。このパラメータの名前は、通常、args
と略される。次のプログラムは、起動時に指定されたすべての引数を表示する。
任意の引数でプログラムを実行しよう:
ほとんどすべてのシステムでは、最初の引数は、ユーザーが入力したとおりにプログラムの名前になる。他の引数は、入力した順番で表示される。
引数の使用方法はプログラムに完全に依存する。次のプログラムは、2つの引数を逆順で表示する:
プログラムは、正確に2つの単語を入力しない場合、正しい使用方法を表示する:
コマンドラインオプションとstd.getopt
モジュール
main()
のパラメータと戻り値について知っておくべきことは、以上だ。しかし、引数の解析は繰り返しの作業だ。std.getopt
モジュールは、プログラムのコマンドラインオプションの解析を支援するために設計されている。
上記の"world"や"hello"のようなパラメータは、プログラムが使用する純粋なデータだ。他の種類のパラメータはコマンドラインオプションと呼ばれ、プログラムの動作を変更するために使われる。コマンドラインオプションの例としては、上記のls
に渡された-l
オプションがある。
コマンドラインオプションは、人間ユーザーがプログラムとインタラクションせずに特定の動作を実行できるようにすることで、プログラムの利便性を高める。コマンドラインオプションを使用すると、プログラムをスクリプトプログラムから起動し、その動作をコマンドラインオプションで指定できる。
各プログラムのコマンドライン引数の構文と意味は、そのプログラムに固有のものだが、その形式は多少標準化されている。例えば、POSIXでは、コマンドラインオプションは--
で始まり、その後にオプションの名前、そして=
文字の後に値が続く。
std.getopt
モジュールは、このようなオプションの解析を簡素化する。このセクションで説明する機能よりも多くの機能を備えている。
乱数を表示するプログラムを作成しよう。これらの乱数の最小値、最大値、および総数をプログラムの引数として受け取る。コマンドラインからこれらの値を取得するには、次の構文を使用しよう。
getopt()
関数は、これらの値を解析して変数に代入する。readf()
と同様に、変数のアドレスは&
演算子で指定する必要がある。
ほとんどのプログラムのコマンドラインオプションには、より短い構文も存在する。例えば、-c
は--count
と同じ意味になる。各オプションのこのような代替構文は、|
文字の後にgetopt()
で指定する。各オプションには複数のショートカットを設定することができる。
短いバージョンには単一のダッシュを使用するのが一般的で、=
文字は通常、省略されるか、スペースに置き換えられる。
getopt()
は、引数をstring
から各変数の型に変換する。例えば、上記のcount
はint
であるため、getopt()
は、--count
引数で指定された値をint
に変換する。必要に応じて、このような変換はto
で明示的に実行することもできる。
これまで、string
への変換にのみstd.conv.to
を使用してきた。to
は、実際には、変換が可能であれば、あらゆる型からあらゆる型に変換することができる。例えば、次のプログラムは、引数をsize_t
に変換する際にto
を利用している。
引数が指定されていない場合、プログラムは10個の数字を出力する:
環境変数
プログラムが起動される環境は、通常、そのプログラムが利用できるいくつかの変数を提供している。環境変数には、std.process.environment
の連想配列インターフェースからアクセスできる。例えば、次のプログラムは、PATH
環境変数を表示する。
出力:
std.process.environment
は、連想配列の構文を使用して環境変数にアクセスする。ただし、environment
自体は連想配列ではない。必要に応じて、toAA()
を使用して環境変数を連想配列に変換することができる:
他のプログラムの起動
プログラムは他のプログラムを開始し、そのプログラムの環境になることができる。これを可能にする関数は、std.process
モジュールにあるexecuteShell
だ。
executeShell
は、そのパラメータを、ターミナルでコマンドが入力されたかのように実行する。そして、そのコマンドの戻りコードと出力をタプルとして返す。タプルは配列のような構造体で、タプルに関する章で後で説明する。
出力:
要約
- 返り値の型が
void
で定義されている場合でも、main()
は成功時には自動的に0を、失敗時には0以外の値を返す。 stderr
はエラーメッセージの表示に適している。main
string[]
をパラメーターとして受け取ることができる。std.getopt
コマンドラインオプションの解析を支援する。std.process
環境変数へのアクセスや他のプログラムの起動を支援する。
演習
- 演算子と2つのオペランドをコマンドライン引数として受け取る計算機プログラムを作成しよう。プログラムは、以下の使用方法をサポートしよう。
注釈:
*
文字は、ほとんどの端末(より正確には、ほとんどのシェル)で特別な意味を持つため、代わりにx
を使用している。\*
とエスケープすれば、*
を使用しても問題はない。 - ユーザーに起動するプログラムを尋ね、そのプログラムを起動し、その出力を表示するプログラムを作成しよう。