C 的 getopt 无法解析 argv 末尾(或中间)的选项

标签 c glibc getopt unistd.h

我爱getopt解析 argv 参数中的选项。不幸的是,我无法使 getopt 解析位于非选项之间或位于 argv 末尾的选项。示例程序:

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

int o_help = 0;

int main(int argc, char *argv[]) {
    int opt, i;
    while ((opt = getopt(argc, argv, "h")) != -1) {
        switch (opt) {
            case 'h':
                o_help = 1;
                break;
            default:
                return -1;
        }
    }

    printf("o_help=%d\n", o_help);
    for (i = 1; i < argc; i++) {
        printf("%s ", argv[i]);
    }
    printf("\n");
    return 0;
}

在 macOS Mojave 上的 alpine 容器中运行该程序,我得到以下输出:

$ gcc prog.c
$ ./a.out hello -h world
o_help=0
hello -h world
$ ./a.out -h hello world
o_help=1
-h hello world

官方 getopt 手册页指出:

By default, getopt() permutes the contents of argv as it scans, so that eventually all the nonoptions are at the end.

由于我没有另外指定,我希望默认行为为 1. 解析 -h 选项并 2. 排列 argv 以便非选项位于末尾数组的。不幸的是,调用像 ./a.out hello -h world 这样的程序既不会解析 -h 也不会排列数组。我们将不胜感激。

最佳答案

Marco 的答案是正确的,但是如果你不使用基于 glibc 的发行版,“自己安装 glibc”确实不是一个好建议;您将自己构建一个完整的并行图书馆生态系统。对于您的问题,有几个更简单的规范解决方案。

GNU 认可的使用非标准 GNU 行为(如您想要的行为)的方法是使用 gnulib 和 autoconf,它可以根据需要自动用 GNU 版本替换 getopt。然而,这是一个重大的改变,它要求您的程序是 GPL 的。

一个更简单的解决方案是仅将 getopt_long 与长选项的简并列表一起使用,而不是 getopt。由于 getopt_long 不是标准管理的函数,而是最初在 GNU 上定义的扩展,因此 musl 的实现可以自由地遵循排列 argv 的 GNU 行为,以允许混合选项和非选项参数,并且这样做。

关于C 的 getopt 无法解析 argv 末尾(或中间)的选项,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60137475/

相关文章:

c - 运行时错误: to create a binary tree

c++ - 插入 std::map 时检测到 glibc(内存错误)

c - 在C中读取unicode文件时出错

c - Getopt - 为缺少的选项和缺少的非选项参数添加大小写

c - 队列弹出一些垃圾值

c - 如何在 Linux 中使用 crypt() 方法?

c - 为什么 printf 在使用 struct 时会有这样的行为?

python -/lib64/libc.so.6 : version `GLIBC_2.14' not found - error from the application build using pyinstaller

c - optarg 值是否在对 getopt 的连续调用中保持不变?

linux - 使用循环解析ksh中的长参数和短参数