在Linux中,较为复杂的C程序命令行参数的解析通常使用getopt, getopt_long以及getopt_long_only来进行,如下所示。
#include <unistd.h>
int getopt(int argc, char *const argv[],
const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
#include <getopt.h>
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_argumentoptional_argument |
flag | flag为0则getopt_long扫描到该参数时返回val,否则将flag指向的变量设置为val |
val | 见flag所述 |
API说明
关于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的索引位置从而完后后续非选项参数的处理
示例
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#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;
}
本文介绍了在Linux中如何使用getopt、getopt_long和getopt_long_only解析C程序命令行参数,包括短选项和长选项的处理,以及关键数据结构和API的使用示例。

1581

被折叠的 条评论
为什么被折叠?



