C 参数解析

2015-11-10 linux language

在 glibc 中提供了一个通用的参数解析库,包括了短参以及长参的使用。

短参

通过 getopt() 函数实现,可以通过循环调用解析参数,当没有多余选项时,会直接返回 -1

全局变量

getopt() 函数的实现中,引入了很多全局变量。

optind

int optind 标识在 argv 中将要检查的下个参数,初始化为 1,如果多次调用 getopt() 或者需要重头开始解析,那么就需要重新将 optind 配置为 1 。

optarg

char *optarg 当使用带参数的选项时,会将 argv[] 中的指针指向该变量。

通过 : 标识选项后有一个参数,可以通过 -c color 或者 -ccolor 使用,注意,一定不要使用 -c=color 方式,此时返回的是 =color

opterr optopt

当遇到不支持的选项时,会在 stderr 中打印错误信息 invalid option -- 'x' (可以通过将 opterr 设置为 0 不打印),同时将选项保存在 optopt 中,并返回 ?

示例

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

int main(int argc, char **argv)
{
        int option, delay = 0;

        opterr = 0;
        while ((option = getopt(argc, argv, "abc:d::")) != -1) {
                switch (option) {
                case 'a':
                        fprintf(stdout, "option -a\n");
                        break;
                case 'b':
                        fprintf(stdout, "option -b\n");
                        break;
                case 'c':
                        fprintf(stdout, "option -c %s\n", optarg);
                        break;
                case 'd':
                        delay = optarg ? atoi(optarg) : 1;
                        fprintf(stdout, "option -d %d\n", delay);
                        break;
                case '?':
                        fprintf(stderr, "unsupport options '%c'\n", optopt);
                        exit(EXIT_FAILURE);
                }
        }

        /* Print remaining arguments. */
        for (; optind < argc; optind++)
                printf("%s\n", argv[optind]);
        return 0;
}

注意事项

只能通过 - 标识选项,对于 getopt() 来说,不能使用 -- 否则会被认为是 - 选项。

--a               报错,无法识别 `-` 选项
-a opt -b         可以正确识别-a和-b选项,并剩余opt参数
-c color -ccolor  带有值的参数

长参

getopt_long()getopt() 类似,可以通过 -- 指定长参数,同时通过函数入参可以指定短参数,如果想只支持长参数,那么需要将 optstring 设置为 "" 而非 NULL

可以使用 --args=param 或者 --args param 指定参数,在解释参数时,需要初始化如下的数组。

struct option {
	const char *name;  // 选项名称
	int has_arg; // no_argument/0 required_argument/1 optional_argument/2
	int *flag; // 可以是NULL或者指针
	int val;   // 根据flag返回
};

根据配置中的 flagval 决定了参数的解析方式,

flag != NULL

会将 val 中的值赋值到 flag 指针所指向的变量,而 getopt_long() 函数会返回 0 ,比较适合整数类型的设置。

flag == NULL

在函数 getopt_long() 中会返回 val 中指定的值,为了方便处理,最好兼容 optstring 中指定的值。

示例

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

int main(int argc, char **argv)
{
        int c, idx, verbose = 0;
        struct option options[] = {
                {"verbose", no_argument,       &verbose, 1  },
                {"add",     no_argument,       NULL,     'a'},
                {"change",  required_argument, NULL,     'c'},
                {"delete",  required_argument, NULL,     0  },
                {0, 0, 0, 0}
        };

        while (1) {
                idx = 0;
                c = getopt_long(argc, argv, "ac:d:", options, &idx);
                if (c == -1) /* Detect the end of the options. */
                        break;
                switch(c) {
                case 0:
                        /* If this option set a flag, do nothing else now. */
                        if (options[idx].flag != NULL)
                                break;
                        printf("option '%s'", options[idx].name);
                        if (optarg)
                                printf(" with arg '%s'", optarg);
                        printf("\n");
                        break;
                case 'a':
                        fprintf(stdout, "option -a\n");
                        break;
                case 'c':
                        printf ("option -c with value '%s'\n", optarg);
                        break;
                case '?':
                        break;
                default:
                        exit(EXIT_FAILURE);
                }
        }

        /* Print remaining arguments (not options). */
        for (; optind < argc; optind++)
                printf("%s\n", argv[optind]);

        return 0;
}