为什么需要命令行解析函数?
当一个用C语言编写的Linux或UNIX程序运行时,它是从main函数开始的。函数声明可以如下:
int main(int argc, char *argv[])
其中argc是程序参数的个数,argv是一个代表参数自身的字符串数组。无论操作系统何时启动一个新程序,参数argc和argv都被设置并传递给main。这些参数通常由另一个程序提供,这个程序一般是shell,它要求操作系统启动该程序。shell接收用户输入的命令行,将命令行分解成单词,然后把这些单词放入argv数组。
例如,如果我们给shell输入如下命令:
$./myprog left right 'and center'
程序myprog将从main函数开始,main的参数值是:
argc:4 argv:{"myprog", "left", "right", "and center"}
注意:参数个数包括程序名自身,argv数组也包含程序名并将它作为第一个元素argv[0]。因为我们在shell命令里使用了引号,所以第四个参数是一个包含了空格的字符串。
在编程的时候,当命令行参数个数较多时,如果按照顺序一个一个定义参数含义很容易造成混乱;如果程序只按顺序处理参数的话,一些“可选参数”的功能将很难实现。为了解决此类问题,GNU C库提供了函数以简化C/C++程序中的解析工作。
getopt_long(int argc, char* argv[], const char *optstring, const struct option *longopts, int *longindex);
注意:getopt头文件为unistd.h,getopt_long额外支持长参数解析,头文件为getopt.h
参数optstring:负责处理短参数。也称为选项指定符字符串,该字符串告诉getopt哪些选项可用,以及它们是否有关联值。optstring只是一个字符列表,每个字符代表一个单字符选项。如果一个字符后面紧跟一个冒号,则表明该选项有一个关联值作为下一个参数。
例:
char *optstring = “abcd:”;
上面这个optstring在传入之后,getopt函数将依次检查命令行是否指定了 -a, -b, -c及 -d(需要多次调用getopt函数,直到其返回-1),当检查到上面某一个参数被指定时,函数会返回被指定的参数名称(即该字母)
最后一个参数d后面带有冒号,:表示参数d是可以指定值的,如 -d 100 或 -d user
参数longopts:负责处理长参数。指向一个由option结构体组成的数组,那个数组的每一个元素都指明了一个长参数(形如”–name”的参数)名称和性质
struct option {
const char* name;
int has_arg;
int *flag;
int val;
}
struct option的解析:
name:参数名称
has_arg:指明是否带参数值,数值可选:
no_argument(即 0)表明这个长参数不带参数(即不带数值,如:--name)
required_argument (即 1) 表明这个长参数必须带参数(即必须带数值,如:--name Bob)
optional_argument(即 2)表明这个长参数后面带的参数是可选的,(即--name和--name Bob均可)
flag
:设置为NULL表示当找到该选项时,getopt_long返回在成员val里给出的值。否则,getopt_long返回0,并将val的值写入flag指向的变量。
val:getopt_long为该选项返回的值。
参数longindex:如果longindex非空,它指向的变量将记录当前找到参数符合longopts里的第几个元素的描述,即是longopts的下标值。
外部变量optarg:在getopt_long循环处理选项时,如果选项有一个关联值,则外部变量optarg指向这个值。
外部变量optind:下一个要读取的参数的下标位置
test.c 完整范例:
/*
在linux下编写的,没安装中文输入法,所以用蹩脚的英文写的注释,懒得删除了
*/
#include
#include
int main(int argc, char *argv[])
{
/*
getopt_long(int argc, char* argv[],
const char* optstring,
const struct option* longopts,
int longindex)
*/
/*
optstring
the ':" after char means it can add a argument
字符后面的 : 表示后面可以加参数
比如 -u 100
*/
char *optstring = "u:d:l:r:t";
int up = 0;
int down = 0;
int left = 0;
int right = 0;
int turn = 0;
/*
longopts
1. name : argument name
2. has_arg : whether need a argument
3. flag : when it is NULL,getopt_long() will return the 'val';
or getopt_long() will set the flag with 'val
4. val : which will use with flag
这里就是定义一个结构option数组,
第一个参数是名字
第二个参数是选择是否需要加参数,选择是了就可以比如 -up 100
第三个参数flag, 如果是空值,getopt_long()就会返回第四个参数val;
如果给的有地址,比如&turn,getopt_long()就会把val的值写入这个地址,返回0
第四个参数val
*/
struct option long_opts[] =
{
{"up", required_argument, NULL, 'u'},
{"down", required_argument, NULL, 'd'},
{"left", optional_argument, NULL, 'l'},
{"right", required_argument, NULL, 'r'},
{"turn", no_argument, &turn, 1},
{NULL, no_argument, NULL, 0}
};
int opt = 0;
int options_index = 0;
/*
反复循环来解析参数,getopt_long执行一次会解析一个参数,如果没有参数就返回-1
如果该参数有值,比如-u 100,则optarg = 100, optind会指向下一个要解析的参数的数组下标
*/
while((opt = getopt_long(argc, argv, optstring, long_opts, &options_index)) != EOF)
{
//optarg is not null
if (optarg)
printf("opt = %d,optarg = %d,optind = %d\n", opt, atoi(optarg), optind);
else
printf("opt = %d\n", opt);
switch(opt)
{
case 0 :
break;
case 'u' :
if(optarg)
up = atoi(optarg);
break;
case 'd' :
if(optarg)
down = atoi(optarg);
break;
case 'l' :
if(optarg)
left = atoi(optarg);
break;
case 'r' :
if(optarg)
right = atoi(optarg);
break;
case 't' :
turn = 1;
break;
}
}
if(turn)
printf("turn,up %d step,down %d step,left %d step,right %d step\n", up, down, left, right);
else
printf("no turn,up %d step,down %d step,left %d step,right %d step\n", up, down, left, right);
}
运行截图:
在测试的时候我发现一个问题,把option的has_arg的值设为optional_argument时候,并没有成为可选,而是没法识别后面的参数,大家可以试一下。
如果有知道为什么的希望可以告知~谢谢!!!
参考文章:http://blog.csdn.net/feglass/article/details/51468857