在Linux中,较为复杂的C程序命令行参数的解析通常使用getopt
, getopt_long
以及getopt_long_only
来进行,如下所示。
#include
int getopt(int argc, char *const argv[],
const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
#include
int getopt_long(int argc, char *const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
int getopt_long_only(int argc, char *const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
其中getopt
仅能用于解析短选项(即以单个-
开头接单个字母的选项,例如-a
,-b
),getopt_long
既可以解析短选项也可以解析长选项(以--
开头,后接一个单词,例如--mode
),getopt_long_only
相比getopt_long
而言可以匹配不规范的长选项(以单个-
开头,后接单词,例如-mode
)。
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
程序接收的短选项可以使用字符串语法进行描述,而长选项需要使用option
结构体来进行描述。
字段 | 说明 |
---|---|
name |
长选项名称 |
has_arg |
是否需要参数,可以设置为no_argument required_argument optional_argument |
flag |
flag 为0 则getopt_long 扫描到该参数时返回val ,否则将flag 指向的变量设置为val |
val |
见flag 所述 |
关于API的使用仅介绍getopt_long
,通常getopt_long
就可以满足需要,其余两个API使用方式也类似。
extern char *optarg;
extern int optind, opterr, optopt;
int getopt_long(int argc, char *const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
参数 | 说明 |
---|---|
argc | main函数的argc参数 |
argv | main函数的argv参数 |
optstring | 描述合法短选项的字符串,字符串中每一个字符表示一个短选项,如果一个字符后紧接一个: 则表示该选项需要一个参数,例如ab:cd: 表示接收四个合法选项,分别为a, b, c, d ,其中b 和d 需要参数。 |
longopts | 描述长选项的数组,见上一小节关键数据结构所述。该数组中最后一项的各个字段需要均为0,表示数组结束(因为这里没有传递数组长度参数) |
longindex | 当getopt_long扫描到一个匹配的长选项时,该指针指向的值被设置为长选项在longopts数组中的索引 |
返回值 | 返回-1表示所有参数已经解析完毕 返回 ? 表示遇到不合法的选项扫描到短选项时返回短选项(短选项为单个字符(char),因此可以使用int表示) 扫描到长选项时返回值见上一小节关键数据结构所述 |
全局变量 | 说明 |
---|---|
optarg | 描述到需要参数的选项时,该变量设置为选项对应的参数 |
optind | 下一个要处理的参数在argv数组中的索引 |
opterr | opterr设置为0时,getopt_long在遇到不合法选项时不会打印错误;设置为1时,则会打印错误信息(默认为1) |
optopt | getopt_long在遇到不合法的短选项时将该变量设置为不合法的短选项 |
getopt_long会调整argv中参数的位置,使得非选项参数均被放到最后边。例如输入参数为
-a pos1 -b pos2 -c pos3
,其中a,b,c
均不接收参数,在解析完参数后,argv中参数变为-a -b -c pos1 pos2 pos3
,我们可以使用optind获取pos1的索引位置从而完后后续非选项参数的处理
详细内容参考getopt(3) - Linux manual page (man7.org)
#include
#include
#include
#define REQUIRED_ARGUMENT_NUM 3
int main(int argc, char* argv[]) {
char* config_filename = NULL;
char* key_filename = NULL;
char* plain_addr = NULL;
char* cipher_addr = NULL;
int i;
// 保存getopt_long返回值
char c;
// long_options的最后一项需要设置为全0表示结束
static struct option long_options[] = {
{"config", required_argument, 0, 0},
{"plain_addr", required_argument, 0, 1 },
{"cipher_addr", required_argument, 0, 2},
{"keyfile", required_argument, 0, 3},
{0, 0, 0, 0 }
};
while (1) {
// 扫描到长选项时获取该选项在long_options数组中的索引
int option_index = 0;
// 第三个参数用于指定合法的短选项
c = getopt_long(argc, argv, "hab",
long_options, &option_index);
// 返回-1表示所有选项扫描完毕
if (c == -1)
break;
// 处理选项参数值,选项参数值保存在全局变量optarg中,为一个字符串
switch (c) {
case 0:
printf("Get %s, value %s\n", long_options[option_index].name, optarg);
break;
case 1:
printf("Get %s, value %s\n", long_options[option_index].name, optarg);
break;
case 2:
printf("Get %s, value %s\n", long_options[option_index].name, optarg);
break;
case 3:
printf("Get %s, value %s\n", long_options[option_index].name, optarg);
break;
case 'a':
printf("Get option a\n");
// 未知选项
case '?':
break;
default:
printf("Unknown return val: %d\n", c);
}
}
// 除了选项,还需要3个位置参数
if (argc - optind != REQUIRED_ARGUMENT_NUM) {
printf("Argumnet error, required %d, get %d\n", REQUIRED_ARGUMENT_NUM, argc - optind);
return -1;
}
// 除了选项,打印3个位置参数
for (i=optind; i < argc; i++) {
printf("position arg %d, value %s\n", i - optind, argv[i]);
}
return 0;
}