前言
本文讲述源码中常见的getopt函数,并为本专栏的RPC项目用到时做准备。
getopt介绍
getopt()函数是用来分析命令行参数的,参数argc和argv分别代表参数个数和内容,跟main()函数的命令行参数是一样的。optstring这个字符串的讲究就比较多了,分析命令行参数的时候就是根据这个字符串来的,将在下面进行介绍。
int getopt(int argc, char * const argv[], const char *optstring);
getopt()会对 argv 中的条目进行顺序处理,其中第一个条目被忽略(对应执行的命令本身的字符串),之后对于 argv 数组中的每一个条目,getopt 将其中使用 '-' 开头的字符串
视为参数项( option element ),参数项中除开始的 ‘-’ 字符外的所有字符被视为参数字符。
getopt的返回值
getopt函数运用一次只会查询一次
,会有中间变量来存储当前的位置的所以循环调用直到返回值为-1代表着结束,参数能正确的按照要求顺序
读出。
getopt正常调用时,会返回对应的合法参数字符对应的ASC码值.当遇到不合法的参数字符时(不包含在 optstring 中),会返回 ‘?’.当所有的命令行条目被解析完成后,getopt 返回 -1。
下面先来个简单的小测试:
#include <iostream>
#include <unistd.h> //需包含的头文件
using namespace std;
int main(int argc, char *argv[]) {
int ret;
ret=getopt(argc,argv,"iabc");
while(ret!=-1){
cout<<char(ret)<<endl;
ret=getopt(argc,argv,"iabc");
}
return 0;
}
结果:
简单来看就是只要参数符合我这个字符串里面的字符的,全都调用正常,能得到起对应的asc码值。如果参数是这样的呢?
( getopt 会维持对应的访问位置的记录,使得下一次对 getopt 的调用会继续上一次的返回位置进行参数的解析)这种情况需要避免,好在这个函数提供了不一样的参数给我们使用。
optstring参数
- 1.单个字符,表示选项。(如上面测试的那样。)
- 2.单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给optarg。(
这是头文件定义的,不需要我们再来定义的,属于全局变量
) - 3 单个字符后跟两个冒号,表示该选项后必须跟一个参数。参数
必须
紧跟在选项后不能以空格隔开
。该参数的指针赋给optarg。(这个特性是GNU的扩张)。 - 4.当 optstring 字符串使用字符 ‘+’ 开始时, getopt 会在遇到第一个非合法参数项时
结束
.而当 optstring 字符串使用 ‘-’ 开始时,所有的非参数项的 argv 数组中的条目均被视为字符值为 1 的参数项的参数,也就是被视为-1 test
形式的调用,getopt 返回值为1
,而 optarg 指向字符串test
. - 5.当 getopt 遇到解析问题时,如遇到非法的参数字符或者某个需要参数的命令行项没有参数时,
默认会通过 stderr 输出错误信息,并将返回值设置为 '?' 。
若在 optstring 中可能存在的 ‘+’ 和 ‘-’ 之后加入 ‘:’,如这样变为"-:i:a::bc"
(注意新加入的 ‘:’ 的位置),则 getopt不会显式的
通过 stderr 输出错误信息,同时在遇到解析错误时,若错误原因为非法参数字符,则 getopt 返回 ‘:’,而若原因为参数项缺少对应的参数,则 getopt 返回 ‘?’.
测试内容
接一个冒号的情况:
#include <iostream>
#include <unistd.h>
using namespace std;
int main(int argc, char *argv[]) {
int ret;
ret=getopt(argc,argv,"i:abc");
while(ret!=-1){
cout<<char(ret)<<endl;
if(optarg!=NULL)printf("%s\n",optarg);
ret=getopt(argc,argv,"i:abc");
}
return 0;
}
接两个冒号的情况:
#include <iostream>
#include <unistd.h>
using namespace std;
int main(int argc, char *argv[]) {
int ret;
ret=getopt(argc,argv,"i:a::bc");
while(ret!=-1){
cout<<char(ret)<<endl;
if(optarg!=NULL)printf("%s\n",optarg);
ret=getopt(argc,argv,"i:a::bc");
}
return 0;
}
开头有个’-':
#include <iostream>
#include <unistd.h>
using namespace std;
int main(int argc, char *argv[]) {
int ret;
ret=getopt(argc,argv,"-i:a::bc");
while(ret!=-1){
cout<<ret<<endl;
if(optarg!=NULL)printf("%s\n",optarg);
ret=getopt(argc,argv,"-i:a::bc");
}
return 0;
}
默认出错:
63为'?'的asc码值。
头文件的相关内容
#include <unistd.h>
extern char *optarg; //选项的参数指针
extern int optind, //下一次调用getopt的时,从optind存储的位置处重新开始检查选项。
extern int opterr, //当opterr=0时,getopt不向stderr输出错误信息。
extern int optopt; //当命令行选项字符不包括在optstring中或者选项缺少必要的参数时,该选项存储在optopt中,getopt返回'?’、
int getopt(int argc, char * const argv[], const char *optstring);
测试代码
#include <iostream>
#include <unistd.h>
using namespace std;
int main(int argc, char *argv[]) {
int ret;
ret=getopt(argc,argv,"iabc");
while(ret!=-1){
cout<<char(ret)<<endl;
cout<<optind<<endl;
if(optarg!=NULL)printf("%s\n",optarg);
ret=getopt(argc,argv,"-i:a::bc");
}
return 0;
}
参考
https://blog.csdn.net/kunikida/article/details/8922754
https://www.cnblogs.com/yhjoker/p/13873739.html