使用`getopt_long`时理解`option long_options []`

时间:2016-10-10 20:11:36

标签: c parameter-passing command-line-arguments getopt getopt-long

我正在努力学会使用getopt_long。从wikipedia开始,我看到代码

#include <stdio.h>     /* for printf */
#include <stdlib.h>    /* for exit */
#include <getopt.h>    /* for getopt_long; POSIX standard getopt is in unistd.h */
int main (int argc, char **argv) {
    int c;
    int digit_optind = 0;
    int aopt = 0, bopt = 0;
    char *copt = 0, *dopt = 0;
    static struct option long_options[] = {
        {"add", 1, 0, 0},
        {"append", 0, 0, 0},
        {"delete", 1, 0, 0},
        {"verbose", 0, 0, 0},
        {"create", 1, 0, 'c'},
        {"file", 1, 0, 0},
        {NULL, 0, NULL, 0}
    };
    int option_index = 0;
    while ((c = getopt_long(argc, argv, "abc:d:012",
                 long_options, &option_index)) != -1) {
        int this_option_optind = optind ? optind : 1;
        switch (c) {
        case 0:
            printf ("option %s", long_options[option_index].name);
            if (optarg)
                printf (" with arg %s", optarg);
            printf ("\n");
            break;
        case '0':
        case '1':
        case '2':
            if (digit_optind != 0 && digit_optind != this_option_optind)
              printf ("digits occur in two different argv-elements.\n");
            digit_optind = this_option_optind;
            printf ("option %c\n", c);
            break;
        case 'a':
            printf ("option a\n");
            aopt = 1;
            break;
        case 'b':
            printf ("option b\n");
            bopt = 1;
            break;
        case 'c':
            printf ("option c with value '%s'\n", optarg);
            copt = optarg;
            break;
        case 'd':
            printf ("option d with value '%s'\n", optarg);
            dopt = optarg;
            break;
        case '?':
            break;
        default:
            printf ("?? getopt returned character code 0%o ??\n", c);
        }
    }
    if (optind < argc) {
        printf ("non-option ARGV-elements: ");
        while (optind < argc)
            printf ("%s ", argv[optind++]);
        printf ("\n");
    }
    exit (0);
}

我不太了解option long_options[]对象。

第一栏

我认为long_options[]的第一个“列”应该是用户在命令行中使用的长标志(跟--之后的任何内容)。

第二栏

我原以为第二列应该只包含no_argumentrequired_arguemntoptional_argument,而不是我看到0和1。

第三栏

我不明白第三栏。

第四列和最大标志数

第四列是在switch语句中使用的唯一标识符。然而,这让我感到困惑,好像唯一标识符只能是单个字符,然后我们只限于所有小写字母(26)+全部大写字母(26)+数字(10)+最终一些特殊字符最多总共超过62个不同的参数。这是getopt的限制吗?如果我弄错了,那么怎么能指出两个以上的字符来标识getopt_long的第三个参数中的一个标志(""abc:d:012""

我认为option long_options[]的最后一行是getopt返回-1的时间,因此只要它存在就无所谓。

1 个答案:

答案 0 :(得分:9)

struct option数组在man getopt_long [注释1]中精确定义,我从中摘录:

  

longopts是指向struct option中声明的<getopt.h>数组的第一个元素的指针

   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 指定如何为长选项返回结果。如果flag为NULL,则getopt_long()会返回val。 (例如,调用程序可以将val设置为等效的短选项字符。)否则,getopt_long()返回0,flag指向设置为{{1}的变量如果找到该选项,但如果找不到该选项则保持不变。

     

val 是要返回或加载到val指向的变量的值。

     

数组的最后一个元素必须用零填充。

因此,您通常会为第二个元素(flag)使用符号常量,但是联机帮助页允许您使用0,1或2,可能是为了向后兼容。 (维基百科应该使用符号常量,恕我直言,但这是维基百科及其编辑之间的。)

has_arg会返回getopt_long,而非int。如果char(第三个)字段为flag(或等效地为0),则将返回NULL(第四个)字段,该字段可以是适合val的任何字段{1}}。一个字符当然适合int,因此您可以返回等效的短选项字符(如联机帮助页中所述),但您没有义务这样做。 int也返回getopt,但由于它总是返回一个选项字符(或错误指示),因此会有大量int值永远不会返回。 [注2]

如果第三个字段不是int,则应指向NULL类型的变量,int将存储getopt_long值。例如,这可以用于布尔标志:

val

如联机帮助页所示,数组中的最后一个条目必须全为零(或指针成员为enum FROBNICATE { FROB_UNSET = -1, FROB_NO = 0, FROB_YES = 1 }; /* ... */ /* This is conceptually an enum, but `getopt_long` expects an int */ int frob_flag = FROB_UNSET; struct option long_opts = { /* ... */ {"frobnicate", no_argument, &frob_flag, FROB_YES}, {"unfrobnicated", no_argument, &frob_flag, FROB_NO}, /* ... */ {NULL, 0, NULL, 0} }; /* Loop over arguments with getopt_long; In the switch statement, you can ignore the returned value 0 because the action has been fully realized by setting the value of a flag variable. */ if (frob_flag == FROB_UNSET) frob_flag = get_default_frobnication(); )。这是必需的,以便NULL知道数组的结束位置。

注释

  1. 您可能已在系统上安装了联机帮助页,在这种情况下,只需键入getopt_long即可查看man getopt_long的文档。这适用于任何标准C库函数,任何Gnu libc函数,以及通常已安装getopt_long包的任何C库函数。 (强烈推荐。)总体而言,在查看Wikipedia之前,您应首先尝试使用manpage ,因为该联机帮助页将是您系统上实际安装的库函数版本的文档。

  2. 函数返回给定数据类型的事实并不意味着它可能返回该数据类型的任何可能值。