getopt, getopt_longについて

getopt

#include <unistd.h>

int getopt(int argc, char * const argv[], const char *optstring);

extern char *optarg;
extern int optind, opterr, optopt;

optstringにはオプションで指定できる文字のリストになっていて、引数を取る場合にはその文字の直後に:を付けることになっている。 例えば、ab:cの場合は-a, -b SOMETHING, -cというオプションが指定できる。

戻り値

  • 見つかったオプション文字を返す。
    • 複数回getoptを呼び出すと、オプション文字を見つかった順番に返すので、getoptはループで使うのが一般的。
    • オプションが引数取る場合、optargに与えられた引数が格納される。
  • 処理するオプションがなくなると、-1を返す。
  • 認識できないオプションにあたると,それをoptoptに格納して、?を返す。
  • 引数を取るオプションなのに、引数がないと:を返す。

optind

  • この後getoptを呼び出すときに、getoptが処理するargvのindexが入っている。
  • 全てのオプションの処理が終わっているとき、optindはargvにある残りの引数のindexを指す。

example

code

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  int opt;

  printf("before loop## optind: %d\n", optind);
  while ((opt = getopt(argc, argv, "ab:c")) != -1) {
    printf("in loop## optind: %d\n", optind);
    printf("in loop## opt: %c\n", opt);
    switch (opt) {
    case 'a':
      printf("in loop## found a option!\n");
      break;
    case 'b':
      printf("in loop## found b option!, -b=%s\n", optarg);
      break;
    case 'c':
      printf("in loop## found c option!\n");
      break;
    case ':':
      printf("in loop## option needs a value\n");
      break;
    case '?':
      printf("in loop## unknown option: %c\n", optopt);
      break;
    }
  }
  for (; optind < argc; optind++) {
    printf("after loop## argument: %s\n", argv[optind]);
  }
  exit(0);
}

output

$ ./a.out -a -b hoge -c hogearg
before loop## optind: 1
in loop## optind: 2
in loop## opt: a
in loop## found a option!
in loop## optind: 4
in loop## opt: b
in loop## found b option!, -b=hoge
in loop## optind: 5
in loop## opt: c
in loop## found c option!
after loop## argument: hogearg

getopt_long

#include <getopt.h>

int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);

getopt_longはロングオプションも処理できる関数になっている。
argc, argv, optstringの意味はgetoptと同じ。

longopts

longoptsに指定する構造体は以下になっている。

struct option {
    const char *name;
    int         has_arg;
    int        *flag;
    int         val;
};
  • name: ロングオプションの名前
  • has_arg: 以下から指定可能。
    • no_argument: 実際の値は0
    • required_argument: 実際の値は1
    • optional_argument: 実際の値は2
  • flag: getopt_longの戻り値の挙動を操作できる。
    • flagがNULLなら、getopt_longはvalの値を返す。
    • flagがNULLでないなら、getopt_longは0を返し、flagのポインタをvalに向ける。

longindex

longindexにNULL以外のintのポインタを渡すと、getopt_longが処理するロングオプションに対応するlongoptsのindexを入れてくれる。

example

#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
  int opt;
  int eflag = 0;
  int longoptind = 0;

  struct option longopts[] = {
      {
          "aaa",
          no_argument,
          NULL,
          'a',
      },
      {
          "bbb",
          required_argument,
          NULL,
          'b',
      },
      {
          "ccc",
          no_argument,
          NULL,
          'c',
      },
      {
          "ddd",
          optional_argument,
          NULL,
          'd',
      },
      {
          "eee",
          no_argument,
          &eflag,
          'e',
      },
  };
  printf("before loop## optind: %d\n", optind);
  printf("before loop## longoptind: %d\n", longoptind);
  while ((opt = getopt_long(argc, argv, "ab:c", longopts, &longoptind)) != -1) {
    printf("in loop## optind: %d\n", optind);
    printf("in loop## longoptind: %d\n", longoptind);

    printf("in loop## opt: %c\n", opt);
    switch (opt) {
    case 'a':
      printf("in loop## found a option!\n");
      break;
    case 'b':
      printf("in loop## found b option!, -b=%s\n", optarg);
      break;
    case 'c':
      printf("in loop## found c option!\n");
      break;
    case 'd':
      printf("in loop## found d option!, -d=%s\n", optarg);
      break;
    case 0: // e
      printf("in loop## found %c option!\n", eflag);
      break;
    case ':':
      printf("in loop## option needs a value\n");
      break;
    case '?':
      printf("in loop## unknown option: %c\n", optopt);
      break;
    }
  }
  for (; optind < argc; optind++) {
    printf("after loop## argument: %s\n", argv[optind]);
  }
  exit(0);
}

output1

getoptのexampleをロングオプションでやってみる。

$ ./a.out -a -b hoge -c hogearg
before loop## optind: 1
in loop## optind: 2
in loop## opt: a
in loop## found a option!
in loop## optind: 4
in loop## opt: b
in loop## found b option!, -b=hoge
in loop## optind: 5
in loop## opt: c
in loop## found c option!
after loop## argument: hogearg

output2

dddロングオプションは引数をとっても、とらなくてもOK。
ロングオプションの指定方法は--LONGOPT=OPTARGの形でなければならないことに注意。

$ ./a.out --ddd fuga
before loop## optind: 1
before loop## longoptind: 0
in loop## optind: 2
in loop## longoptind: 3
in loop## opt: d
in loop## found d option!, -d=(null)
after loop## argument: fuga
$ ./a.out --ddd=fuga
before loop## optind: 1
before loop## longoptind: 0
in loop## optind: 2
in loop## longoptind: 3
in loop## opt: d
in loop## found d option!, -d=fuga

output3

eeeロングオプションの例(flagにNULLじゃない値を渡している。)

./a.out --eee
before loop## optind: 1
before loop## longoptind: 0
in loop## optind: 2
in loop## longoptind: 4
in loop## opt:
in loop## found e option!