getopt()不返回下一个参数

时间:2019-11-26 05:22:40

标签: c getopt

看看下面的代码:-

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

int main(int argc, char *argv[]){
    char ch;
    int value;
    while((ch = getopt(argc, argv, "n: o"))!=EOF){
        switch(ch){
            case 'n':
                value = atoi(optarg);
                fprintf(stdout,"\nParameter n");
                //Do something
                break;
            case 'o':
                fprintf(stdout,"\nParameter 0");
                //Do something
                break;
            default:
                fprintf(stdout,"\nInvalid!");
        }
        argc -= optind;
        argv += optind;
    }
}

当我传递以下参数时

./program -n 123 -o

我得到这个结果

Parameter n

我希望得到这个

Parameter n
Parameter o

为什么getopt()在循环的第二次迭代中不返回下一个参数?

更新

所以代码应该像这样:-

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

int main(int argc, char *argv[]){
    char ch;
    int value;
    while((ch = getopt(argc, argv, "n:o"))!=-1){
        switch(ch){
            case 'n':
                value = atoi(optarg);
                fprintf(stdout,"Parameter n (%d)\n", value);
                //Do something
                break;
            case 'o':
                fprintf(stdout,"Parameter o\n");
                //Do something
                break;
            default:
                fprintf(stdout,"Invalid!\n");
                break;
        }
    }
}

1 个答案:

答案 0 :(得分:2)

主要问题

在循环内部,您可以:

    argc -= optind;
    argv += optind;

那是一场灾难-不要这样做。您可以在循环完成后(一次)使用这些语句,但不能在循环主体中使用这些语句。它强制代码跳过选项。在严重的情况下,它最终可能会尝试解析空指针或环境,而这两者都可能无济于事(并且两者都是未定义的行为,因此是YMMV)。

切线问题

请注意,您已指定空格为选项之一。这样有人可以写:

./a.out -' ' -n 123 -o

,空格将被视为标志选项(例如-o)。这可能与您的想法不符。使用"n:o",且其中没有空格。

您打印:

fprintf(stdout,"\nParameter 0");

该声明的三个小问题:

  1. 0应该是o-它们是不同的。
  2. 在输出格式的末尾而不是在开头放置换行符(除非您想要双倍行距)。请注意,在打印换行符之前可能不会生成输出,因此末尾的换行符可确保打印的数据显得更及时。
  3. 使用fprintf(stdout, …)而不是printf(…)是一种惯例。并非完全错误,但不寻常。

POSIX将getopt()函数定义为在完成选项处理后返回-1而不返回EOF。这样一来,它在<unistd.h>中的声明就不会与EOF<stdio.h>的定义有关。 (“基本原理”部分明确指出: getopt()函数应返回-1,而不是EOF,因此不需要<stdio.h>)历史上,系统在getopt()中声明了<stdio.h>,但是POSIX将其放置在<unistd.h>中并说它返回了-1

您应在交换机中break;后面加上一个default:。这是一项基本的防御性编程措施,即使有人在default:标签之后添加了另一个case标签,它也可以确保不会掉线。