前言
   
本文讲述源码中常见的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
    
   
 
