我正在尝试学习使用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的,因此只要它存在就没有关系。

最佳答案

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

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

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


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

getopt_long返回int,而不是char。如果flag(第三)字段是NULL(或等价的0),则将返回val(第四)字段,并且可以是适合int的任何内容。字符肯定适合int,因此您可以返回等效的短选项字符(如联机帮助页中所述),但您没有义务这样做。 getopt也返回int,但是由于它总是返回选项字符(或错误指示),因此有很多int值将永远不会返回。 [笔记2]

如果第三个字段不是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)。这是必需的,以便getopt_long知道数组在哪里结束。

笔记


您可能已经在系统上安装了手册页,在这种情况下,您只需键入man getopt_long即可查看getopt_long的文档。这对于任何标准C库函数,任何Gnu libc函数,以及通常为您安装了-doc软件包的任何C库函数都适用。 (强烈建议。)总体而言,在查看Wikipedia之前,应先尝试使用手册页,因为该手册页将是系统上实际安装的库函数版本的文档。
函数返回给定数据类型的事实并不意味着它可能返回该数据类型的任何可能值。

07-28 03:04
查看更多