getopt_long() 带有可选参数的选项

getopt_long() option with optional argument

我正在尝试使用 getopt_long() 创建一个带有可选参数的选项。

这是我的代码:

static struct option long_options[] = {
   {"help",   no_argument,      NULL, 'h'},
   {"debug",  no_argument,      NULL, 'd'},
   {"config", optional_argument, NULL, 'c'},
   {NULL, 0, NULL, 0}
};

while ((ch = getopt_long(argc, argv, "hdc::", long_options, NULL)) != -1) {
        // check to see if a single character or long option came through
        switch (ch) {
            case 'h':
                opt.help = true;
                break;
            case 'd':
                opt.debug = true;
                break;
            case 'c':
                printf("C-Option: %s\n", optarg);
                if (optarg != NULL) {
                    opt.configFile = optarg;
                }
                break;
        }
    }

我正在尝试使 -c 的参数可选,这样您就可以 运行 使用这些选项的程序:

-c test.cfg --> optarg = "test.cfg"

-c --> optarg = null

如果我设置 c::,那么 optarg 总是 null

如果我设置 c: 比我得到一个错误:option requires an argument -- 'c'

我做错了什么?我可以设置其他选项吗?

来自man pages

If the option has an optional argument, it must be written directly after the option character if present.

您的代码按预期工作:

./a.out -c some_argument --> "C-Option: (null)"
./a.out -csome_argument  --> "C-Option: some_argument"
./a.out -c=some_argument --> "C-Option: =some_argument"

您可以考虑在可选参数名称前加上 '=',如上例所示。 another question 讨论了这个问题。

更新

我在上面提到的 link 到 other question 中看到了这个问题的一个很好的解决方案。这个想法是在带有参数的选项之后检查 argv[] 中的下一个字符串是否是一个选项。如果不是,则假定它是一个参数。然后处理该参数,并相应地推进 optind。以下是如何将此想法应用于您的问题:

case 'c':
            if (optarg == NULL && argv[optind] != NULL
                && argv[optind][0] != '-') {            // not an option
                printf("C-Option: %s\n", argv[optind]);
                opt.configFile = argv[optind];
                ++optind;
            } else {  // handle case of argument immediately after option
                printf("C-Option: %s\n", optarg);
                if (optarg != NULL) {
                    opt.configFile = optind;
            }
            break;

此代码将产生以下输出:

./a.out -csome_argument  --> "C-Option: some_argument"
./a.out -c some_argument --> "C-Option: some_argument"