注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

落叶清风L的博客

努力向前

 
 
 

日志

 
 
 
 

对getopt()和getopt_long()的一点小认识  

2013-07-25 01:23:41|  分类: linuxC |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
     在写一个带有命令行参数的函数时,例如:
     ./my_ls -l -a -i -R
     对于解析参数,若是自己手动去解析,却是有些耗费人力精力,四个参数4!种组合!!!寻之捷径,有两个库提供的函数可以帮住我们很方便地去解析这些参数。接下来就对这两个函数认识一下:
     对于getopt()函数:
#include <unistd.h>
int getopt ( int argc , char * const argv[] , const char * optstring);
     其中对于 argc 与 argv[] , 和main函数的参数相同,只要传递就好。
对于optstring 参数 则是对参数的控制字符串,像printf中的格式控制字符串一样。具体是这样的:
     在unistd.h中定义了这样的几个全局变量:

      extern char *optarg; //选项的参数指针,未找到参数时被赋值为NULL

      extern int optind,   //下一次调用getopt的时,从optind存储的位置处重新开始检查选项。 
 
     extern int opterr,  //当opterr=0时,getopt不向stderr输出错误信息。-c
 
     extern int optopt;  //当命令行选项字符不包括在optstring中或者选项缺少必要的参数时,该选项存储在optopt 中,getopt返回'?'

     每一次调用getopt就会返回一个选项字符,如果再也找不到optstring中包含选项时返回-1

     这里需要介绍以下什么是选项什么是参数:

     选项:单个字符,表示选项

     参数:单个字符后接一个冒号:表示该选项后必须跟一个参数。参数紧跟在选项后或者以空格隔开。该参数的指针赋给全局的指针变量optarg。当单个字符后跟两个冒号,表示该选项后可以跟一个参数或者不跟。但是如果有参数必须紧跟在选项后不能以空格隔开。该参数的指针赋给optarg。

    例如:gcc  -o -g test.c test

     其中o和g是选项,test是-o的参数

     来一个详细的例子

     我们这样去调用optget( argc , argv , "ab:cd::" );

     由上面的知识大家可以理解到ac后面都没有参数,b后面有一个参数,d后面可能有参数,如果有的话一定紧跟在d后面。getopt首先扫描argv[1]到argv[argc-1],并将选项及参数依次放到argv数组的最左边,非选项参数依次放到argv的最后边。

     好了,有了这些知识,我们再看看这个函数是如何实现的。我们给一段代码:


$ ./temp file -b file1 -dfile2 file4 -c -a

     这条命令扫描过程中,optind是下一个选项的索引(相当于数组的下表index,是argv[optind]的索引), 非选项参数将跳过,同时optind增1。optind初始值为1。当扫描argv[1]时,非选项跳过,并将参数file放置argv[6],optind=2;扫描到-b选项时, 判断有参数,将-b放置argv[1],将参数file1放置-b之后即argv[2] ;optind 更改为4,扫描到-d选项时,判断有参数,将-dfile2一起放入argv[3]中,optind=5,判断非选项,跳过并将file4放置 argv[7],optind=6扫描到-c,没有参数 ,将-c放置argv[4],optind=7扫描到-a,没有参数将-a放置argv[5]。完成后optind指向第一个参数;

上命令执行结果如下所示:

(b appear)Her name is XZ.
(d appear)Let's we come together!
(c appear)Our love is just like the sun and the moon!
(a appear)My name is XR.
argv[0] = ./temp
argv[1] = -b
argv[2] = file1
argv[3] = -dfile2
argv[4] = -c
argv[5] = -a
argv[6] = file
argv[7] = file4

程序的源码如下:

01 #include <getopt.h>
02 #include <unistd.h>
03 #include <stdio.h>
04 
05 char *l_opt_arg;  
06 char* const short_options = "ab:cd::";  
07 /*struct option long_options[] = {  
08          { "name",     0,   NULL,    'f'     },  
09          { "bf_name",  0,   NULL,    'g'     },  
10          { "love",     1,   NULL,    'h'     },  
11          {      0,     0,     0,     0},  
12 };*/  
13 int main(int argc, char *argv[])  
14 {  
15          int i;
16          int c;  
17          while((c = getopt (argc, argv, short_options/*  , long_options, NULL*/)) != -1)  
18          {  
19               switch (c)  
20               {  
21                  case 'a':  printf("(a appear)My name is XR.\n"); break;  
22                  case 'b':  printf("(b appear)Her name is XZ.\n"); break;  
23                  case 'c':  printf("(c appear)Our love is just like the sun and the moon!\n" ); break;
24                  case 'd':  printf("(d appear)Let's we come together!\n"); break;                  
25                  case 'f':  printf("(name apper)OK .Now I will tell you my love!\n"); break;
26                  case 'g':  printf("(bf_name appear) I really need you !\n"); break;
27                  case 'h':  printf("(love appear) I will stay here and never leave !\n"); break;
28                  case '?':  printf("(? appear)Lack arguments!");
29               }  
30          }
31          for ( i = 0 ; i < argc ; i++)
32              printf("argv[%d] = %s\n" , i , argv[i] );
33                    return 0;  
34 }

关于optget_long的实现,optget_long是支持长选项的命令行解析函数 ,也就是类似于这样的--help , --more等等,它可以解析这样的参数

上面的代码一样可以使用,去掉注释部分,就可以了

#include <getopt.h>

函数原型:

int getopt_long(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
函数中的argc和argv通常直接从main()到两个参数传递而来。optsting是选项参数组成的字符串,和getopt()函数相同的意思。下一个参数是指向数组的指针,这个数组是option结构数组,option结构称为长选项表,其声明如下:
 struct option {
              const char *name;    
              int has_arg;
              int *flag;
              int val;
          };
结构中的元素解释如下:
const char *name:选项名,前面没有短横线,也就是除过杠的部分 如:"help"、"verbose"之类。
int has_arg:描述长选项是否有选项参数,如果有,是哪种类型的参数,其值见下表:
符 号常 量                   数值            含义
no_argument                0            选项没有参数
required_argument       1            选项需要参数
optional_argument        2            选项参数是可选的
int *flag:
     如果该指针为NULL,那么getopt_long返回val字段的值,这个val就是将来要出现在case,选项里的标志,另外一个理解,相当于给name在程序判断时重新起了个名字,用这个来判断是否出现了name这个选项;
     如果该指针不为NULL,那么会使得它所指向的结构填入val字段的值,同时getopt_long返回0
     int val:如果flag是NULL,那么val通常是个字符常量,如果短选项和长选项一致,即-和--后面的选项一致,那么该字符就应该与optstring中出现的这个选项的参数相同;
     最后一个参数:longindex参数一般赋为NULL即可;如果没有设置为NULL,那么它就指向一个变量,这个变量会被赋值为寻找到的长选项在 longopts中的索引值,这可以用于错误诊断。机体怎样实现的,小编在这里就不多深入了,有兴趣的geeker可以继续研究。

     口说无凭,还是给个例子吧:
    

$ ./temp --name --bf_name --love hello -a -b world -c -d

    看看结果吧:

tutu@tutu-Latitude-E6400 ~/file $ ./temp --name --bf_name --love hello -a -b world -c -d
(name apper)OK .Now I will tell you my love!
(bf_name appear) I really need you !
(love appear) I will stay here and never leave !
(a appear)My name is XR.
(b appear)Her name is XZ.
(c appear)Our love is just like the sun and the moon!
(d appear)Let's we come together!

     它轻松实现了长选项的情况。所以,大家以后在解析命令行参数的时候,尽量还是使用库函数,十分地方便,省了自己很多的精力.
     在这里和大家交流,希望写的有问题的地方,多多指教~!~
                                                                                                                                             ----------------------引用百度百科内容

                                                                                                                                             ----------------------引用ast_224(CSDN)的博文

                                                                                                                                             ----------------------十分感谢汤秋媛和小江同学

  评论这张
 
阅读(73)| 评论(2)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018