该文主要介绍c语言通过命令行方式输入参数,程序如何获取并解析参数。
例如:./a.out -a red -b blue
当你输入上面的命令,你想将red值赋给a,blue值赋给b。当然你可以通过解析argv数组来获取(getopt系列肯定也是这么干的)。
1. 接口介绍
1.1 getopt
1.1.1 函数原型
#include <unistd.h>
int getopt(int argc, char * const argv[],
const char *optstring);
extern char *optarg;
extern int optind, opterr, optopt;
1.1.2 简介
getopt()函数用于解析命令行参数,以-
开头的argv元素是选项元素,重复调用getopt()函数将返回每个选项元素的选项字符。
eg.当你输入./a.out -a red -b blue
,将得到
argc=5
argv={
"0" => "./a.out"
"1" => "-a"
"2" => "red"
"3" => "-b"
"4" => "blue"
}
-a
和-b
就是选项参数,第一次调用getopt将返回a
,第二次调用将返回b
。
当getopt()找到一个选项字符之后,它首先返回该字符,更新外部变量optind和一个静态变量nextchar。当遍历所有的选项字符,没有多余的选项之后,getopt()函数返回-1
变量optind是argv中要处理的下一个元素索引。重复调用之后,该值累加。可将该值重置,重新获取参数选项。
optstring是一个包含合法选项字符的字符串。若字符后跟一个冒号,则该选项需要一个参数,getopt()设置一个指针指向同一个argv元素的下一个文本中;两个冒号表示该选项需要一个可选的参数。
1.1.3 示例
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
/*
* 打印参数列表
*/
printf("argc=%d\n",argc);
for(int i=0;i<argc;i++) {
printf("argv[%d]=%s ",i, argv[i]);
}
printf("\n");
int opt,flags;
char *avalue,*bvalue;
flags = 0;
char *optstring = "a:b:c";
while ((opt = getopt(argc, argv, optstring)) != -1) {
switch(opt) {
case 'a':
flags = 1;
avalue = optarg;
break;
case 'b':
flags = 2;
bvalue = optarg;
break;
case 'c':
flags = 3;
break;
default:
flags = 5;
}
}
printf("flags=%d; optind=%d; avalue=%s; bvalue=%s\n", flags, optind, avalue,bvalue);
exit(EXIT_SUCCESS);
}
编译运行:
~ gcc getopt.c -o getopt -Wall
~ ./getopt -b d -a a
argc=5
argv[0]=./getopt argv[1]=-b argv[2]=d argv[3]=-a argv[4]=a
flags=1; optind=5; avalue=a; bvalue=d
1.2 getopt_long()
允许长参数名
1.2.1 函数原型
#include <getopt.h>
int getopt_long(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
1.2.2 简介
getopt_long()函数相对于getopt(),增加了长参数列表。
longopts指向一个由option结构体组成的数组。option结构体定义在<getopt.h>中:
struct option {
const char *name; //参数完整名称
int has_arg; //该参数是否带有参数值
int *flag; //一般设置为NULL
int val;
};
- name:长参数名称
- has_arg:设定这个长参数是否带参数值
- no_argument/0:不需要参数值
- required_argument/1:需要一个参数值
- optional_argument/2:表明其后面是否带参数值都可以
- flag:设定一个长参数如何返回
- NULL:getopt_long()返回val。
- 非空:val的值会被赋到flag指向的整型数中,而函数返回值为0
- val:函数找到该选项时的返回值,或当flag非空时指定flag指向的数据的值
该数组最后一个参数需要设置为0。
如果longindex不为NULL,则它指向一个变量,该变量设置为long选项相对于longopts的索引。
1.2.3 实例
#include <stdio.h> /* for printf */ #include <stdlib.h> /* for exit */ #include <getopt.h>
int main(int argc, char **argv) {
int c;
int digit_optind = 0;
while (1) {
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] = {
{"add", required_argument, 0, 0 },
{"append", no_argument, 0, 0 },
{"delete", required_argument, 0, 0 },
{"verbose", no_argument, 0, 0 },
{"create", required_argument, 0, 'c'},
{"file", required_argument, 0, 0 },
{0, 0, 0, 0 }
};
c = getopt_long(argc, argv, "abc:d:012",
long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 0:
printf("option %s", long_options[option_index].name);
if (optarg)
printf(" with arg %s", optarg);
printf("\n");
break;
case '0':
case '1':
case '2':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf("option %c\n", c);
break;
case 'a':
printf("option a\n");
break;
case 'b':
printf("option b\n");
break;
case 'c':
printf("option c with value '%s'\n", optarg);
break;
case 'd':
printf("option d with value '%s'\n", optarg);
break;
case '?':
break;
default:
printf("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc) {
printf("non-option ARGV-elements: ");
while (optind < argc)
printf("%s ", argv[optind++]);
printf("\n");
}
exit(EXIT_SUCCESS);
}
2. 使用总结
谁也没法天生就知道如何优雅的使用,从笨拙到放弃才是常态:),我这里总结了模板,仅供参考,与openssl里将getopt里将其封装相比,思想上差的不是一星半点。
2.1 蹒跚学步
/*
* 命令行参数列表
*/
static struct option long_options[] = {
{"mode",1,0,'m'},
{"algorithom",1,0,'a'},
{"key_HEX",0,0,'k'},
{"iv_HEX",0,0,'v'},
{"input",0,0,'i'},
{"output",0,0,'o'},
{"format",1,0,'f'},
{"help",0,0,'h'}
};
while( (c = getopt_long(argc,argv,"m:a:k:v:i:o:f:h",long_options,&option_index)) != -1){
switch(c){
case 'm':
//optarg此时指向参数值
break;
}
}
网友评论