コマンドライン引数の使い方 -

コマンドライン引数の使い方 -main 関数の書き方 -
プログラムの動作を実行時に変えたい場合どうすればよいだろうか?
1.端末にメッセージを出し、動作パラメータを入力する。
2.プログラム実行時にコマンドライン引数として渡す。
1の方法はよく使われる。例えば UNIDAQ Offline Analyzer では、
int main()
{
char RawFileName[100];
char HistoFileName[100]:
printf( "RawFileName ?:");
scanf( "%s", RawFileName );
printf( "HistoFileName ?:" );
scanf( "%s", HistoFileName );
...
return 0;
}
こんな感じになっている。(ただし、scanf をつかって入力を読むのは一般的には止めたほうがよい。) ただしこのスタ
イルで問題ないわけではない。
1.対話的実行では問題とはならないが、バッチ処理には向かない。
シェルスクリプトでヒアドキュメントの手法を使えば可能ではある。
#/bin/sh
./offanalyzer << eof
rData/r0000101.dat
HBook/run0000101.hbook
eof
2.その他にも重要な入力・出力がある場合、使いにくい。フィルタといって、標準入力からデータを読み、何らかの加
工を行って、標準出力に書き出すプログラムでは、入力データと動作パラメータを分離しなければならない。
このような場合、プログラム実行時にコマンドラインパラメータとして、プログラムに渡せばよい。例えば、上の例では、
# ./offanalyzer rDara/r0000101.dat HBook/run0000101.hbook
として、実行できればいろいろと便利である。
一般に、シェルはプログラム起動時のコマンドラインの入力行の空白文字列を終端文字('¥0')に変換して、プログラ
ムから参照できるメモリ上にコピーする。上の例では、以下のような領域が確保される。
|
|
|
|
+ -- -- -- -- -- -- -- -- -- +
|
|
|
|
+ -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +
|
|
argv[1]
argv[2]
>
argv[0]
>
>
>
. / o f f a n a l y z e r \0 r D a t a / r 0 ... a t \0 H B ... o k \0
|
argv
」
図中の矢印は、ポインタの指す先を表している。文字列で区切られたコマンドラインの内容が入っている無名の領域、
各文字列へのポインタの配列(図中には argv[0] と書いたが無名)、およびその配列へのポインタ変数 argv が確保
される。(argv という名前は後述)
C/C++での main 関数は次の2通りのいづれかで定義(宣言)しなければならない。
int main( void );
int main( int argc, char **argv );
よく、main の戻り値は無い( void )と書かれた本があるが、(パソコン系のコンパイラの教科書に多い。) そんな本を
信じてはいけない。 ANSI C/C++ では int 型である。
さて、main 関数の2番目の型で渡される引数について説明する。第1引数 argc は、コマンドラインで渡される文
字列の数を表す。第2引数 argv は、上の図で説明した通り、 char 型へのポインタのポインタである。 char **argv
の変わりに、 char *argv[] と宣言することもある。char * は文字列(の先頭へのポインタ)を表すので、argv[0],
argv[1], ... によってコマンドラインで渡された文字列にアクセスできる。argc 以上の添字を使ったアクセスは未定義な
のでやってはいけない。
コマンドライン引数を使ったプログラム例を示す。ファイル名の文字列を string 型に代入する。string 型は、C++で
導入された型で安全な文字列処理ができる。C で書く場合はメモリ確保に気をつけて C 文字列( char * )を使うこと。
#include <string>
#include <cstdio>
int main( int argc, char **argv )
{
if( argc<3 ){
fprintf( stderr, "Usage: %s <RawFileName> <HistoFileName> ¥n", argv[0] );
exit(0);
}
std::string RawFileName = argv[1];
std::string HistoFileName = argv[2];
FILE *fp = fopen( RawFileName.c_str(), "r" );
...
return 0;
}
最後に、C プログラムは main 関数で始まるとかかれているが、正確にはこれは正しくない。Startup Code と呼ばれる
コードの実行後、main 関数が呼び出される。C++の場合は、コンストラクタがあるため、静的変数領域に置かれるオブ
ジェクトのコンストラクタの実行後、main 関数が呼び出される。これらのコンストラクタの呼び出し順序は規格では決め
られていない。また、main 関数の終了後には、これらのオブジェクトのデストラクタ呼び出しがある。