为什么C getopt_long_only()没有为未知选项设置optopt?

时间:2018-12-18 07:36:52

标签: c getopt

我正在尝试将const galImg = $(‘.gallery-images’); 与自定义错误消息一起使用。代码如下所示。我尝试设置opterr = 0并在optstring的开头使用冒号来禁用内置错误消息。我添加了一个用布尔值getopt_long_only()控制的代码块,以尝试自定义错误消息,例如,当使用诸如optoptWorks = true之类的错误选项时,显示一条消息。但是-z始终设置为0,而我正在使用的optopt错误消息没有任何意义。对于自定义消息,“:”(冒号)错误(缺少参数,例如?)确实可以正常工作。关闭内置错误消息并在-d中进行处理似乎会导致?始终设置为0,因此我无法打印有问题的选项(optopt)。我在Debian Linux gcc 4.9.4和Cygwin gcc 7.3.0上进行了编译,并且都给出了相同的结果。似乎-z is not recognized可能没有正确设置getopt_long_only()还是我错过了什么? Web上的许多示例都通过使用内置错误消息或仅打印用法来解决此问题,而没有告诉用户无法识别哪个选项。

此处输出optopt

optoptWorks=false

这是$ ./testoptget -z testoptget: unknown option -- z -d # Set the debug level. -h, --help Print program usage. -q Run in quiet mode (log messages to syslog but not console). -v, --version Print program version. $ ./testoptget -d testoptget: option requires an argument -- d -d # Set the debug level. -h, --help Print program usage. -q Run in quiet mode (log messages to syslog but not console). -v, --version Print program version. 的输出:

optoptWorks=true

代码如下:

$ ./testoptget -z
[ERROR] Unknown option character '\x0'.

-d #            Set the debug level.
-h, --help      Print program usage.
-q              Run in quiet mode (log messages to syslog but not console).
-v, --version   Print program version.

$ ./testoptget -d
[ERROR] Option '-d' is missing argument.

-d #            Set the debug level.
-h, --help      Print program usage.
-q              Run in quiet mode (log messages to syslog but not console).
-v, --version   Print program version.

1 个答案:

答案 0 :(得分:3)

找到未知的长选项时,

optopt确实设置为零,请参见here。但是在我看来,您可以使用optind - 1作为argv中的索引来打印有问题的选项,因为optindgetopt返回{{ 1}}。

据我了解,您的目标是仅指定自定义错误消息。

也来自man getopt_long:

  

如果optstring的第一个字符(在上述任意可选的'+'或'-'之后)是冒号(':'),则getopt()同样不会显示错误消息。此外,它返回“:”而不是“?”表示缺少选项参数。这使调用者可以区分两种不同类型的错误。

您引用的文档与'?'有关,而不与getopt有关。 here确实说getopt_long_only,但是getopt_long() function works like getopt()被设置为“选项字符”。如果是长选项,则没有“选项字符”,而是“选项字符串”(如我所称)-在我看来将optopt设置为零是合理的。

因此,根据optstring中的初始字符,将返回optopt:,如已实现的man getopt_long_onlyherehere一样。

以下程序是您的程序,其中已删除注释,缩短了用法功能,将?替换为exit,并仅用return添加了打印违规选项:

printf("%s", argv[opting - 1]);

输出:

#include <ctype.h>
#include <getopt.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int debug = 0;

void usage(void) { printf("-- insert usage here --\n"); }

void parseargs(int argc,char **argv)
{
    static struct option long_options[] = {
        { "help",    no_argument, 0, 'h' },
        { "version", no_argument, 0, 'v' },
        { 0,         0,           0, 0 }
    };
    int long_index = 0;
    int opt;
    int errorCount = 0;

    optind = 1;

    while((opt = getopt_long_only(argc, argv, ":d:hqv", long_options, &long_index)) != -1) {
        switch (opt) {
            case 'd':
                debug = atoi(optarg);
                break;
            case 'h':
                usage();
                return;
                break;
            case 'q':
                break;
            case 'v':
                break;
            case ':':
                fprintf(stderr, "[ERROR] Option '-%c' is missing argument.\n", optopt);
                ++errorCount;
                break;
            case '?':
                if (optopt == 0) {
                    fprintf(stderr, "[ERROR] Unknown option '%s'.\n", argv[optind - 1]);
                } else {
                    fprintf(stderr, "[ERROR] Error parsing option '-%c'\n", optopt);
                }
                ++errorCount;
                break;
        }
    }
    if ( errorCount > 0 ) {
        usage();
        return;
    }
}

int main(int argc, char **argv)
{

#define SIZE(x) (sizeof(x)/sizeof(*x))
    struct {
        int argc;
        char **argv;
    } tests[] = {
        { 2, (char*[]){ argv[0], (char[]){"-z"}, NULL, } },
        { 2, (char*[]){ argv[0], (char[]){"-d"},  NULL, } },
    };

    for (int i = 0; i < SIZE(tests); ++i) {
        printf("\n## test tests[i].argv[1] = %s\n", tests[i].argv[1]);
        parseargs(tests[i].argc, tests[i].argv);
    }

    return 0;
}

如果将optstring设置为## test tests[i].argv[1] = -z [ERROR] Unknown option '-z'. -- insert usage here -- ## test tests[i].argv[1] = -d [ERROR] Option '-d' is missing argument. -- insert usage here -- ,但不加前导"d:hqv",则它属于:的情况,即然后程序返回:

?