Google gflags库(解析命令行参数)

google gflags是google使用的一个开源库,用于解析命令行标记。目前的gflags有C++和Python两个版本。本文主要介绍gflags的C++版本使用方法。

命令行标记是指用户在运行可执行程序时,在命令行中指定的参数。例如,对于命令:

[plain]  view plain  copy
  1. fgrep -l -f /var/tmp/foo johannes brahms  

-l-f /var/tmp/foo是两个命令行标记,而johnnesbrahms则是命令行参数。一个应用往往具有许多个命令行标记,对应这些标记,可以传入一些由用户指定的参数。例如,在上面的例子中,-l标记没有任何参数,而-f标记的参数则是/var/tmp/foo

这些标记和参数存储在main函数的argcargv参数中。一般而言,main函数总有如下的形式:

[cpp]  view plain  copy
  1. int main(int argc, char ** argv) {…}  

其中argc指明了argv数组的长度,而argv数组则空格为分割,存储命令行后用户输入的参数。在GNU C Library中,这个工作主要是由getopt函数来完成的。以下是getopt函数的一个例子:

[cpp]  view plain  copy
  1. #include <ctype.h>  
  2.   
  3.  #include <stdio.h>  
  4.   
  5.  #include <stdlib.h>  
  6.   
  7.  #include <unistd.h>  
  8.   
  9.    
  10.   
  11.  int  
  12.   
  13.  main (int argc, char **argv)  
  14.   
  15.  {  
  16.   
  17.    int aflag = 0;  
  18.   
  19.    int bflag = 0;  
  20.   
  21.    char *cvalue = NULL;  
  22.   
  23.    int index;  
  24.   
  25.    int c;  
  26.   
  27.    
  28.   
  29.    opterr = 0;  
  30.   
  31.    
  32.   
  33.    while ((c = getopt (argc, argv, "abc:")) != -1)  
  34.   
  35.      switch (c)  
  36.   
  37.        {  
  38.   
  39.        case 'a':  
  40.   
  41.          aflag = 1;  
  42.   
  43.          break;  
  44.   
  45.        case 'b':  
  46.   
  47.          bflag = 1;  
  48.   
  49.          break;  
  50.   
  51.        case 'c':  
  52.   
  53.          cvalue = optarg;  
  54.   
  55.          break;  
  56.   
  57.        case '?':  
  58.   
  59.          if (optopt == 'c')  
  60.   
  61.            fprintf (stderr, "Option -%c requires an argument.\n", optopt);  
  62.   
  63.          else if (isprint (optopt))  
  64.   
  65.            fprintf (stderr, "Unknown option `-%c'.\n", optopt);  
  66.   
  67.          else  
  68.   
  69.            fprintf (stderr,  
  70.   
  71.                     "Unknown option character `\\x%x'.\n",  
  72.   
  73.                     optopt);  
  74.   
  75.          return 1;  
  76.   
  77.        default:  
  78.   
  79.          abort ();  
  80.   
  81.        }  
  82.   
  83.    
  84.   
  85.    printf ("aflag = %d, bflag = %d, cvalue = %s\n",  
  86.   
  87.            aflag, bflag, cvalue);  
  88.   
  89.    
  90.   
  91.    for (index = optind; index < argc; index++)  
  92.   
  93.      printf ("Non-option argument %s\n", argv[index]);  
  94.   
  95.    return 0;  
  96.   
  97.  }  

 在这个例子中可以看出,所有的标记的定义都必须要集中在一个地方处理(也就是switch代码段中)。而gflags则与getopt函数不同,在gflags中,标记的定义分散在源代码中,不需要列举在一个地方。这意味着单个的源代码文件可以定义他们自己所使用的标记,一切连接到这个文件的应用将获取这个标记,并且gflags将自动对这个标记进行适当的处理。这对于软件的灵活性及代码的重用是很有好处的。当然,这也产生了一定的风险,特别是,两个不同的文件可能会定义拥有同一个名字的命令行标记,在平常的情况下没有问题,但当这两个文件被同一个二进制程序连接的时候,就会出现错误。

gflags使用C++语言实现,其风格也是C++风格的。本文的其余部分介绍了如何使用gflags。

一、如何定义一个命令行标记

使用gflags需要引用gflags头文件:

#include <gflags/gflags.h>

在gflags.h文件的结尾,定义了一些标记定义宏,因此在引用了gflags.h后,定义一个命令行标记就变得十分简单了。如,在foo.cc文件的开头,我们引入如下的命令行标记的定义:

[cpp]  view plain  copy
  1. #include <gflags/gflags.h>  
  2.   
  3. DEFINE_bool(big_menu, true"Include 'advanced' options in the menu listing");  
  4. DEFINE_string(languages, "english,french,german”,"comma-separated list of languages to offer in the 'lang' menu");  

 

在这段代码中,我们定义了两个命令行标记:bool型的big_menu,以及string型的language。所有的DEFINE宏都有三个参数:标记的名字,默认值,以及针对这个标记的说明。第三个参数是非常有用的,尤其是在构建大型程序的时候,在命令行中使用—help标记可以列出被gflags所定义的所有标记的类型、默认值及对其的说明(也就是宏第三个参数)。

DEFINE宏支持的类型包括:

o    DEFINE_bool: boolean

o    DEFINE_int32: 32-bit integer

o    DEFINE_int64: 64-bit integer

o    DEFINE_uint64: unsigned 64-bit integer

o    DEFINE_double: double

o    DEFINE_string: C++ string

可以在可执行程序的任何一个源文件中定义一个标记,而针对每个标记,只需要定义一次。如果想要在不同的源文件中访问该标记,可以使用DECLARE宏来声明这个标记(其实就是声明了一个extern变量的引用)。一个更好的方法是,对于一个标记,可以在foo.cc中定义它,并且在foo.h中声明它。这样,包含了foo.h的所有源文件都可以引用这个标记。

二、如何访问一个标记

访问标记较为简单。只要对标记进行了定义或者声明,那么只需要在使用它的地方加上前缀“FLAGS_”就可以引用这个标记了。如,

[cpp]  view plain  copy
  1. if (FLAGS_consider_made_up_languages)  
  2.   
  3. FLAGS_languages += ",klingon";   // implied by --consider_made_up_language  
  4.   
  5. if (FLAGS_languages.find("finnish") != string::npos)  
  6.      HandleFinnish();  

三、在命令行中使用标记

对于上面的foo.cc和foo.h,如果其编译后产生的二进制文件为app_containing_foo,则在命令行中设置这些标记的方法为:

app_containing_foo --nobig_menu -languages="chinese,japanese,korean" …

这个命令会把big_menu设置为false,并且将language设置为“chinese,japanese,Korean”。对于string、int、double等类型的标记,设置标记时使用如下形式:

o    app_containing_foo --languages="chinese,japanese,korean"

o    app_containing_foo -languages="chinese,japanese,korean"

o    app_containing_foo --languages "chinese,japanese,korean"

o    app_containing_foo -languages "chinese,japanese,korean"

这些方式是等价的。但注意gflags不支持短标记与合并标记。如ls –la这种类型,是不能够被gflags处理的。这和getopt函数有所不同。

 需要注意的还有以下几点:

1,--连用会终止标记。如命令:foo -f1 1 -- -f2 2,则f2标记将不被处理;

2,bool型的标记,如big_menu,既可以使用—big_menu=true/false,也可以使用—big_menu/--nobig_menu这种方式。gflags都可以解析。

3,使用未被定义的标记将引发严重错误。

四、在程序中解析标记

在程序中解析标记可以使用如下函数:

[cpp]  view plain  copy
  1. google::ParseCommandLineFlags(&argc, &argv, true);  

注意argc和argv均以地址方式传递,也就是该函数可以改变argc和argv的内容。通常这段代码会出现在main函数的开始。最后一个参数是移除标记,它指明了是否将被gflags成功解析的标记从参数列表中移除。例如,对于命令行:

foo –options=start file1 file2

在这个命令行中,options是一个命令行标记,将被gflags解析(如果它已经被定义了);而file1和file2则是命令行参数。如果设置remove标记位ture,则—options=start会在调用ParseCommandLineFlags后被移除,此时argc=2,而argv中则保存了file1和file2两个参数。如果remove标记位设为false,则—options=start将不会被移除,则argc不会改变,但argv会重新排列,将所有的标记排列在前面。


学习资料参考于:

<<用Google的gflags优雅的解析命令行参数>>

http://www.leoox.com/?p=270

<<google gflag使用指南>>

http://blog.csdn.net/starays/article/details/7990984

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值