getopt() 解析模式不起作用

getopt() parsing mode not working

根据联机帮助页,getopt()有三种不同的解析模式

By default, getopt() permutes the contents of argv as it scans, so that eventually all the nonoptions are at the end. Two other modes are also implemented. If the first character of optstring is '+' or the environment variable POSIXLY_CORRECT is set, then option processing stops as soon as a nonoption argument is encountered. If the first character of optstring is '-', then each nonoption argv- element is handled as if it were the argument of an option with character code 1. (This is used by programs that were written to expect options and other argv-elements in any order and that care about the ordering of the two.) The special argument "--" forces an end of option-scanning regardless of the scanning mode.

在我的 Centos 7 上,'+'/'-' 符号似乎无法切换解析模式,它们都给出相同的结果,这是我的测试代码:

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

void parse(int argc, char * const argv[], const char *optstr)
{
    printf("opterr: %d optstr: %s optargs: ", opterr, optstr);
    for (int i = 0; i < argc; ++i) {
        printf("%s ", argv[i]);
    }
    printf("\n");

    int opt = -1;
    optind = 1;
    while ((opt = getopt(argc, argv, optstr)) != -1) {
        printf("optind: %d optopt: %d "
               "optarg: %s opt: %c\n",
               optind, optopt, optarg, (char)opt);
    }

    printf("unparsed: ");
    for (int i = optind; i < argc; ++i) {
        printf("%s ", argv[i]);
    }
    printf("\n");
}

void nonoption()
{
    const char *optstr = "ab";
    char *argv[] = {"", "-a", "hello", "-b", "world"};
    parse(5, argv, optstr);
}

void posix_nonoption()
{
    const char *optstr = "+ab";
    char *argv[] = {"", "-a", "hello", "-b", "world"};
    parse(5, argv, optstr);
}

void nonoption1()
{
    const char *optstr = "-ab";
    char *argv[] = {"", "-a", "hello", "-b", "world"};
    parse(5, argv, optstr);
}

int main(int argc, char *argv[])
{
    nonoption();
    posix_nonoption();
    nonoption1();
    return 0;
}

这是输出:

opterr: 1 optstr: ab optargs:  -a hello -b world
optind: 2 optopt: 0 optarg: (null) opt: a
optind: 4 optopt: 0 optarg: (null) opt: b
unparsed: hello world
opterr: 1 optstr: +ab optargs:  -a hello -b world
optind: 2 optopt: 0 optarg: (null) opt: a
optind: 4 optopt: 0 optarg: (null) opt: b
unparsed: hello world
opterr: 1 optstr: -ab optargs:  -a hello -b world
optind: 2 optopt: 0 optarg: (null) opt: a
optind: 4 optopt: 0 optarg: (null) opt: b
unparsed: hello world

如果你看一下 getopt manual 你会发现这段话:

A program that scans multiple argument vectors, or rescans the same vector more than once, and wants to make use of GNU extensions such as '+' and '-' at the start of optstring, or changes the value of POSIXLY_CORRECT between scans, must reinitialize getopt() by resetting optind to 0, rather than the traditional value of 1. (Resetting to 0 forces the invocation of an internal initialization routine that rechecks POSIXLY_CORRECT and checks for GNU extensions in optstring.)

您必须在函数parse中将optind设置为0,然后才能生效。