2012年10月10日水曜日

C言語のプログラムにコマンドラインオプションを付ける

UNIX系のコマンドの後に-(ハイフン)と一緒に英語を付けたオプションをよく目にしますよね。
例えば
ls -a
とか
ln -s
とか
rm -d -f
など。

こういうオプションを自分で作れる方法があります。
オプションを付ける利点は、コンパイル時ではなく実行時にパラメータを変更できるというのもありますが、これから説明する方法を使うと引数の順番を気にしなくて良くなります。
さらにプログラムの使用方法なんかを表示させるオプションも付けられるので、久々に使うプログラムも困惑せずに使うことが出来ます。

ではやり方。
使うのはgetopt関数というもので、<getopt.h>をインクルードします。
僕もこの関数の仕様なんかはあまり分からず今のところテンプレに従って使っているだけなので、ここでは簡単な説明だけに留めておきます。
以下がテンプレ。
 
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>

static option options[] =
  {
    {"help", no_argument, NULL, 'h'},
    {"input", required_argument, NULL, 'i'},
    {"output", required_argument, NULL, 'o'},
    {"parameter", required_argument, NULL, 'p'},
    {"simple_version", no_argument, NULL, 's'},
    {0, 0, 0, 0}
  };

int main(int argc, char *argv[])
{
  char *input;
  char *output;
  int para;
  bool simple_ver = false;

  int c;
  int index;

  while((c = getopt_long(argc, argv, "hi:o:p:s", options, &index)) != -1){
    switch(c){
    case 'h':
      printf("Usage: This program is an example.\n");
      printf("       -i: Input file name.\n");
      printf("       -o: Output file name.\n");
      printf("       -p: Giving a parameter.\n");
      printf("       -s: Executing a simple program.\n");

      exit(0);

    case 'i':
      input = optarg;
      break;

    case 'o':
      output = optarg;
      break;

    case 'p': 
      para = atoi(optarg);
      break;
      
    case 's':
      simple_ver = true;
      break;

    default:
      std::cerr << "Error: An unknown option is appointed.\n";
      exit(1);
    }
  }

 ...
}

このソースがコンパイル通るかどうかは謎ですが、順に説明していきます。
まずmain関数外で定義されているoptions[]ですが、 これはoptionという型名の構造体の配列で、option型はgetopt.hにグローバル変数として定義してあります。
ここに使用したいオプションの名前を書いていきますが、メンバ変数の順番はまず最初にオプションの長い名前、次にそのオプションが引数を取るのかどうか(no_argumentrequired_argument)、3番目は必ずNULL、4番目にアルファベット1文字だけのオプション名を書きます。
そしてこの配列の最後は必ず{0, 0, 0, 0}の要素で埋めます。
これで-h, -i, -o, -p, -sというオプションが使えるようになります。

そしてmain関数内で具体的な挙動を定義します。
ここでは実際に使っているのはgetopt_longという関数です。
int型のc(charの方が良いのかも)にコマンドラインで指定された引数が格納されます。
getopt_long関数の引数には、main関数の引数であるargc, argv、そしてoptionsで作ったオプションを文字列として与えます。
:(コロン)の意味は、直前のオプションが引数を取ることを意味し、これがoptionsの引数(no_argumentrequired_argument)と間違っていると、コンパイルか実行時にエラーが出るはずです。
indexは多分何番目の引数なのかを格納するためだと思います。

そしてcに関するswitch文でオプションごとの挙動を定義していきます。
optargというのはgetopt.h内で定義されたグローバル変数で、 各オプションの引数が格納されます。
たとえば、
./program -i inputFile.dat -o outputFile.dat -p 3 -s

のように実行したとします。
すると、iのオプションのときはoptarg="inputFile.dat"となり、oのオプションのときはoptarg="outputFile"といった具合になります。
./program -h

でhelp文を表示できます。

getopt関数とは違い、getopt_long関数はoptionsで指定した長い名前の形式でもオプションを指定できます。
つまり
./program --help

これで-hのオプションを指定したのと同じ挙動になります。

わーわー言うとりますけども、お時間です。
かなり分かりづらい説明なので、質問、訂正なんかがあればコメントください。

0 件のコメント :

コメントを投稿