用Google的gflags轻松的编码解析命令行参数

支持的参数类型

gflags支持的类型有bool,int32,int64,uint64,double和string。可以说这些基本类型大体上满足了我们的需求。

  1. DEFINE_bool: boolean
  2. DEFINE_int32: 32-bit integer
  3. DEFINE_int64: 64-bit integer
  4. DEFINE_uint64: unsigned 64-bit integer
  5. DEFINE_double: double
  6. DEFINE_string: C++ string

比如上文中,我就定义了confPath, port, daemon三个命令行参数,回顾一下:

1

2

3

DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");

DEFINE_int32(port, 9090, "program listen port");

DEFINE_bool(daemon, true, "run daemon mode");

稍微讲解一下:

  • 第一个字段 confPath就是命令行里要输入的参数名,比如 –confPath=./love.ini
  • 第二个字段”../conf/setup.ini”,就是如果命令行里没指定这个参数,那默认值就是 ../conf/setup.ini
  • 第三个字段”program configure file.”,就是这个参数的帮助说明信息,当用户输入 –hlep 的时候,会显示出来。

代码中使用这个变量

以前我们使用getopt_long函数来自己解析命令行参数的时候,都得内部定义一个变量来保存从命令行得到的值。后续就可以使用这个变量来完成相应的代码逻辑。那其实,DEFINE_string等“指令”就相当于定义了变量,只不过变量名多了个前缀 “FLAGS_“。即,我们可以在代码里面直接操作FLAGS_confPath,FLAGS_port,FLAGS_port,FLAGS_daemon这三个变量。

解析命令行参数

gflags是使用ParseCommandLineFlags这个方法来完成命令行参数的解析的。具体如下:

1

gflags::ParseCommandLineFlags(&argc, &argv, true);

一目了然,唯一值得注意的就是第三个参数了。如果设置为true,gflags就会移除解析过的参数。即argc, argv就会变了。否则gflags还会保持这些参数继续留在argc,argv中。但是参数的顺序有可能会发生变化。

如果不好理解的话,没关系,来一段代码就明白什么意思了。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

#include <iostream>

#include <gflags/gflags.h>

using namespace std;

DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");

DEFINE_int32(port, 9090, "program listen port");

DEFINE_bool(daemon, true, "run daemon mode");

int main(int argc, char** argv)

{

for (int i = 0; i < argc; i++) {

printf("argv[%d] = %s\n", i, argv[i]);

}

printf("---------------here--------------\n");

gflags::SetVersionString("1.0.0.0");

gflags::SetUsageMessage("Usage : ./demo ");

gflags::ParseCommandLineFlags(&argc, &argv, true);

for (int i = 0; i < argc; i++) {

printf("argv[%d] = %s\n", i, argv[i]);

}

printf("---------------there--------------\n");

cout << "confPath = " << FLAGS_confPath << endl;

cout << "port = " << FLAGS_port << endl;

if (FLAGS_daemon) {

cout << "run background ..." << endl;

}

else {

cout << "run foreground ..." << endl;

}

cout << "good luck and good bye!" << endl;

gflags::ShutDownCommandLineFlags();

return 0;

}

运行后,看一下true的情况:

1

2

3

4

5

6

7

8

9

10

11

12

[amcool@leoox build]$ ./demo --port=8888 --confPath=./happy.ini --daemon

argv[0] = ./demo

argv[1] = --port=8888

argv[2] = --confPath=./happy.ini

argv[3] = --daemon

---------------here--------------

argv[0] = ./demo

---------------there--------------

confPath = ./happy.ini

port = 8888

run background ...

good luck and good bye!

修改为false,在运行一下的情况:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

[amcool@leoox build]$ ./demo --port=8888 --confPath=./happy.ini --daemon

argv[0] = ./demo

argv[1] = --port=8888

argv[2] = --confPath=./happy.ini

argv[3] = --daemon

---------------here--------------

argv[0] = ./demo

argv[1] = --port=8888

argv[2] = --confPath=./happy.ini

argv[3] = --daemon

---------------there--------------

confPath = ./happy.ini

port = 8888

run background ...

good luck and good bye!

参数检查

按照以前的习惯,我们可以获取到所有参数的值后,再在代码里面进行判断这个参数是否是我们想要的。比如,我们需要端口是36800 到 36888之间的,那我们可以这样检查。

1

2

3

4

if (FLAGS_port < 36800 || FLAGS_port > 36888) {

printf("port must [36800, 36888]\n");

return -1;

}

当然gflags里面建议使用 RegisterFlagValidator 这个方法来做参数检查。参数不通过的时候,程序是启动失败的。

1

2

3

4

5

6

7

8

9

10

11

static bool ValidatePort(const char* flagname, gflags::int32 value) {

if (value >= 36800 && value <= 36888) {

printf("param(%s) = (%d) is valid!\n", flagname, value);

return true;

}

printf("param(%s) = (%d) is invalid!\n", flagname, value);

return false;

}

DEFINE_int32(port, 36810, "program listen port");

static const bool validPort = gflags::RegisterFlagValidator(&FLAGS_port, &ValidatePort);

运行一下,看看效果:

1

2

3

4

[amcool@leoox build]$ ./demo --port=36889 --confPath=./happy.ini --daemon

param(port) = (36889) is invalid!

param(port) = (36810) is valid!

ERROR: failed validation of new value ‘36889‘ for flag ‘port‘

【疑问】:我们手动指定端口36889不合法,默认的36810合法。怎么让gflags当发现参数不合法的时候,使用合法的默认参数呢?!

其他代码文件使用参数变量

正常来说,我们的代码不可能只有1个cpp,还会有很多模块。而每个模块可能会使用到不同的参数值。所以我们之前在demo.cpp定义的参数变量(比如FLAGS_port),在其他模块怎么引用和使用呢?so easy,与DEFINE相对应的有DECLARE。声明一下,就可以使用了。

  1. DECLARE_bool: boolean
  2. DECLARE_int32: 32-bit integer
  3. DECLARE_int64: 64-bit integer
  4. DECLARE_uint64: unsigned 64-bit integer
  5. DECLARE_double: double
  6. DECLARE_string: C++ string

来一段简单的代码,就一目了然啦。

示例代码目录结构

1

2

3

4

5

6

7

8

9

10

[amcool@leoox demo]$ tree

.

|-- CMakeLists.txt

|-- build

|-- demo.cpp

|-- logic.cpp

`-- logic.h

1 directory, 4 files

[amcool@leoox demo]$

logic.h

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

#ifndef _LEOOX_LOGIC_H_

#define _LEOOX_LOGIC_H_

#include <iostream>

#include <gflags/gflags.h>

using namespace std;

DECLARE_string(confPath);

DECLARE_int32(port);

DECLARE_bool(daemon);

int process();

#endif

logic.cpp

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

#include "logic.h"

int process()

{

printf("----------------- process start ---------------\n");

cout << "confPath = " << FLAGS_confPath << endl;

cout << "port = " << FLAGS_port << endl;

if (FLAGS_daemon) {

cout << "run background ..." << endl;

}

else {

cout << "run foreground ..." << endl;

}

printf("----------------- process end ---------------\n");

return 0;

}

demo.cpp

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

#include "logic.h"

DEFINE_string(confPath, "../conf/setup.ini", "program configure file.");

DEFINE_bool(daemon, true, "run daemon mode");

static bool ValidatePort(const char* flagname, gflags::int32 value) {

if (value >= 36800 && value <= 36888) {

printf("param(%s) = (%d) is valid!\n", flagname, value);

return true;

}

printf("param(%s) = (%d) is invalid!\n", flagname, value);

return false;

}

DEFINE_int32(port, 36810, "program listen port");

static const bool validPort = gflags::RegisterFlagValidator(&FLAGS_port, &ValidatePort);

int main(int argc, char** argv)

{

gflags::SetVersionString("1.0.0.0");

gflags::SetUsageMessage("Usage : ./demo ");

gflags::ParseCommandLineFlags(&argc, &argv, false);

process();

cout << "good luck and good bye!" << endl;

gflags::ShutDownCommandLineFlags();

return 0;

}

CMakeLists.txt

1

2

3

4

5

6

7

8

9

10

project(demo)

cmake_minimum_required(VERSION 2.8)

set(CMAKE_VERBOSE_MAKEFILE on)

include_directories(".")

include_directories("/home/leoox/local/gflags-2.1.1/include")

link_directories("/home/leoox/local/gflags-2.1.1/lib")

add_executable(demo demo.cpp logic.cpp)

target_link_libraries(demo gflags pthread)

运行结果

1

2

3

4

5

6

7

8

9

10

[amcool@leoox build]$ ./demo --port=36850 --confPath=./love.ini

param(port) = (36850) is valid!

param(port) = (36850) is valid!

----------------- process start ---------------

confPath = ./love.ini

port = 36850

run background ...

----------------- process end ---------------

good luck and good bye!

[amcool@leoox build]$

至此,Google的强大的开源组件之一的“gflags”,就算完成了深入浅出的学习了。自己以后可以把getopt_long深藏功与名了。哈哈。

转自:http://www.leoox.com/?p=275

时间: 2024-08-24 01:01:40

用Google的gflags轻松的编码解析命令行参数的相关文章

boost之program_options库,解析命令行参数、读取配置文件

一.命令行解析 tprogram_options解析命令行参数示例代码: [cpp] view plaincopy #include <iostream> using namespace std; #include <boost/program_options.hpp> namespace po = boost::program_options; int main(int argc, char*argv[]) { //int level; po::options_descripti

flag 是Go 标准库提供的解析命令行参数的包QANDA.REN文库

flag flag 是Go 标准库提供的解析命令行参数的包. 使用方式: flag.Type(name, defValue, usage) 其中Type为String, Int, Bool等:并返回一个相应类型的指针. flag.TypeVar(&flagvar, name, defValue, usage) 将flag绑定到一个变量上. 自定义flag 只要实现flag.Value接口即可: type Value interface { String() string Set(string)

解析命令行参数的方法

一.关于解析命令行参数的方法 关于"解析命令行参数"的方法我们一般都会用到sys.argv跟optparse模块.关于sys.argv,网上有一篇非常优秀的博客已经介绍的很详细了,大家可以去这里参考:https://www.cnblogs.com/aland-1415/p/6613449.html 这里为大家介绍一个比sys.argv更强大的optparse模块. 这里说一句题外话,点开optparse的源码,第一行注释是这样的:A powerful, extensible, and

3.QT中QCommandLineParser和QCommandLineOption解析命令行参数

 1  新建项目 main.cpp #include <QCoreApplication> #include <QCommandLineParser> #include <QDebug> #include <stdio.h> int main(int argc, char** argv) { QCoreApplication app(argc, argv); app.setApplicationVersion("1.0.0.0");

Python3-argparse模块-解析命令行参数

官方文档 http://python.usyiyi.cn/translate/python_352/library/argparse.html 代码示例 import argparse # 1.获取参数解析对象 parser = argparse.ArgumentParser(description="帮助信息前的一些描述信息,可以不写哦") # 2.添加可解析的参数 # add_argument()函数常用参数 # name or flags 选项字符串的名字或列表,例如foo或者

getopt_long函数解析命令行参数

转载:http://blog.csdn.net/hcx25909/article/details/7388750 每一天你都在使用大量的命令行程序,是不是感觉那些命令行参数用起来比较方便,他们都是使用getopt来实现的. 在Linux下使用getopt写程序是一种比较cool的事情,下面来简单的介绍一下getopt的使用. === getopt使用 === 在讨论参数处理之前,我们先明确两个概念:选项.选项参数gcc -g -o test test.c我们经常使用上面的命令来编译程序,这里g和

Python3+getopt解析命令行参数

一.说明 在学C语言的时候就知道可以通过argc获取命令行参数个数,可以通过argv获取具体参数.但自己写的程序获取到的参数一是没有键值形式二是写的参数不能乱序,和系统命令不太一样. 再往后点知道有getopt这个东西,但印象中尝试理解其用法很多次都没什么结果:最近又越来多写程序,再次感觉很有必要掌握. 这里以Python3为例演示getopt,python感觉就是C的封装,C的getopt应该也类似. 二.程序代码 此程序中设置-h/-n/-p三个选项,-h不带值-n和-p带值:三个参数设置等

Linux getopt/getopts解析命令行参数教程

一.说明 shell中获取参数可以直接使用$1.$2等形式来获取,但这种方式有明显的限制:每个参数的位置是固定的.比如如果在设计上$1是ip地址$2是端口,那在执行时就必须第一个参数是ip第二个参数是端口而不能反过来. shell提供了getopt和getopts来解析参数,getopt比getopts功能强一些getopts比getopt简单一些:总体而言getopt和getopts都差强人意. 二.使用getopt解析参数 getopt比getopts强一些复杂一些:能在命令行中单独使用.支

java解析命令行参数(common-cli)练习

package foo; import org.apache.commons.cli.BasicParser; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.Options; public class test { public static void main(String[] args) thro