使用getopt_long()第二遍不起作用

时间:2018-04-27 13:31:45

标签: c

我想在例程中使用getopt_long()两次,以便在解析其他所有内容之前可以设置详细标记,但不知何故,函数的第二次调用不会按预期处理参数。这是一个演示该问题的简化代码。有人有任何线索吗?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>

static void processInput(int argc, const char **argv) {
    int k;
    int verbose = 0;
    struct option long_options[] = {
        {"help"   , no_argument, NULL, 'h'},
        {"verbose", no_argument, NULL, 'v'},
        {0, 0, 0, 0}
    };
    // Construct short_options from long_options
    char str[1024] = "";
    for (k = 0; k < sizeof(long_options) / sizeof(struct option); k++) {
        struct option *o = &long_options[k];
        snprintf(str + strlen(str), 1023, "%c%s", o->val, o->has_arg == required_argument ? ":" : (o->has_arg == optional_argument ? "::" : ""));
    }
    // First pass: just check for verbosity level
    int opt, long_index = 0;
    while ((opt = getopt_long(argc, (char * const *)argv, str, long_options, &long_index)) != -1) {
        printf("Processing %c\n", opt);
        switch (opt) {
            case 'v':
                verbose++;
                break;
            default:
                break;
        }
    }

    //
    // Add verbose flag here to show something while setting up
    //

    // Second pass: now we go through all of them.
    long_index = 0;
    while ((opt = getopt_long(argc, (char * const *)argv, str, long_options, &long_index)) != -1) {
        printf("Processing %c\n", opt);
        switch (opt) {
            case 'h':
                printf("Help text here\n");
                break;
            case 'v':
                // Add a dummy line here so that '-v' does not trigger the default task
                break;
            default:
                fprintf(stderr, "I don't understand: -%c   optarg = %s\n", opt, optarg);
                exit(EXIT_FAILURE);
                break;
        }
    }
}


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

    processInput(argc, argv);

    return EXIT_SUCCESS;
}

2 个答案:

答案 0 :(得分:1)

全局变量optindargc例程结束时增加到getopt_long(),因此第二遍不会更进一步。为了让函数从头再次重新处理所有内容,需要重置全局变量optind。所以,添加

// Second pass: now we go through all of them.
optind = 1;
long_index = 0;

答案 1 :(得分:1)

如上所述,是getopt_long

的手册页
  

变量optind是argv中要处理的下一个元素的索引。系统将此值初始化为1.调用者可以将其重置为1以重新开始扫描相同的argv,或者扫描新的参数向量。

所以你必须在第二遍之前将optind设置为1.

    // Second pass: now we go through all of them.
    optind = 1;
    long_index = 0;
    while ((opt = getopt_long(argc, (char * const *)argv, str, long_options, &long_index)) != -1) {
        printf("Processing %c\n", opt);
        switch (opt) {
            case 'h':
                printf("Help text here\n");
                break;
            case 'v':
                // Add a dummy line here so that '-v' does not trigger the default task
                break;
            default:
                fprintf(stderr, "I don't understand: -%c   optarg = %s\n", opt, optarg);
                exit(EXIT_FAILURE);
                break;
        }
    }

小小的警告:关于男人,还有这个说明:

  

一个程序,它扫描多个参数向量,或多次重新扫描同一个向量,并希望使用GNU扩展,例如&#39; +&#39;和&#39; - &#39;在optstring的开头,或者在扫描之间更改POSIXLY_CORRECT的值,必须通过将optind重置为0来重新​​初始化getopt(),而不是传统的值1.(重置为0强制调用重新检查POSIXLY_CORRECT的内部初始化例程和检查optstring中的GNU扩展。)

所以要小心并选择最适合你情况的东西。