getopt和getopt_long

这篇笔记选自Using getopt。 一个典型的的Unix程序格式如下:

getopt [-dmp] [-s name] -f name file [file ...]

a)dmp是可选option,在一个[]中表示它们可以一起使用;

b)[-s name]表示s是一个带参数的可选option
c)-f name表示f是一个带参数的必选option
d)file [file ...]表示程序还需要一个或多个命令行参数。
getopt函数原型如下:

#include <unistd.h>

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

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

需要注意以下几点:

a)每次调用getopt后,如果option带参数,optarg指向后面跟着的参数;optind则表示下一次处理optionindex。因此当getopt解析完所有option后,如果同argc相同,则表示没有命令行参数。
b)getopt前两个参数直接从main函数参数得到,第三个参数指定如何处理option"df:mps:"。冒号表示前面的option后面需要带参数。如果getopt解析option时遇到不在optstring中的option返回?,把option全部解析完返回-1
下面看一下getopt_longgetopt_long_only(参考getopt(3) – Linux man page):

#include <getopt.h>

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

getopt_long除了可以处理short option外,还可以处理long option(以--开头)。关于struct option定义如下:

struct option {
    const char *name;
    int         has_arg;
    int        *flag;
    int         val;
};
The meanings of the different fields are:
name
is the name of the long option.

has_arg
is: no_argument (or 0) if the option does not take an argument; required_argument (or 1) if the option requires an argument; or optional_argument (or 2) if the option takes an optional argument.  

flag
specifies how results are returned for a long option. If flag is NULL, then getopt_long() returns val. (For example, the calling program may set val to the equivalent short option character.) Otherwise, getopt_long() returns 0, and flag points to a variable which is set to val if the option is found, but left unchanged if the option is not found.

val
is the value to return, or to load into the variable pointed to by flag.

如果flagNULLgetopt_long会返回val的值,因此通常会把flag置成NULL,把val置成与long option对应的short option。否则getopt_long会返回0,并把val的值赋给flag

参考下列代码(选自GNU binutils中的size命令)可以更好地了解getopt_long

#define OPTION_FORMAT (200)
#define OPTION_RADIX (OPTION_FORMAT + 1)
#define OPTION_TARGET (OPTION_RADIX + 1)

static struct option long_options[] =
{
  {"common", no_argument, &show_common, 1},
  {"format", required_argument, 0, OPTION_FORMAT},
  {"radix", required_argument, 0, OPTION_RADIX},
  {"target", required_argument, 0, OPTION_TARGET},
  {"totals", no_argument, &show_totals, 1},
  {"version", no_argument, &show_version, 1},
  {"help", no_argument, &show_help, 1},
  {0, no_argument, 0, 0}
};


 while ((c = getopt_long (argc, argv, "ABHhVvdfotx", long_options,
               (int *) 0)) != EOF)
    switch (c)
      {
      case OPTION_FORMAT:
    switch (*optarg)
      {
      case 'B':
      case 'b':
        berkeley_format = 1;
        break;
      case 'S':
      case 's':
        berkeley_format = 0;
        break;
      default:
        non_fatal (_("invalid argument to --format: %s"), optarg);
        usage (stderr, 1);
      }
    break;

    ......

    case 0:
    break;
    ......
    }

{"format", required_argument, 0, OPTION_FORMAT}flagNULL,所以getopt_long返回值是OPTION_FORMAT;根据optarg确定应该使用哪种format。而{"totals", no_argument, &show_totals, 1}flagNULLgetopt_long返回值是0show_totals的值为1

getopt_longgetopt_long_only的区别:

getoptlongonly() is like getopt_long(), but ‘-‘ as well as “–” can indicate a long option. If an option that starts with ‘-‘ (not “–“) doesn’t match a long option, but does match a short option, it is parsed as a short option instead.