简介
Abseil标志库允许对通过命令行传递给可执行程序的标志值进行编程访问。其实就是对命令行参数进行解析,并可快速访问的一个工具库。
Abseil Flags库提供了以下特性:
-
以线程安全的方式访问Abseil标志
-
在程序生命周期的任何点都可以访问有效的标志值
-
确保同一进程内的唯一性,防止标志名称冲突
-
提供内置的用法提供的关联帮助文本
-
支持布尔型、整型和字符串类型等,并可扩展以支持其他Abseil类型和自定义类型
-
支持默认值,并可对标志值的进行读写
-
允许在不同地方声明和定义标志,尽管这种用法有缺点,通常应该避免。
标志的值由absl:: parsecommanline()从命令行解析。 每个标志的结果值存储在一个未指定类型的全局变量absl:: flag 中。
flags库的介绍和使用详见官网:flags
限制
-
因命令行参数的长度是有限制的,根据各系统定义不一致。因此对输入参数较长的慎用该方式。
-
windows命令行最大长度为 8191 个字符,详细介绍见:命令行字符串限制
-
linux命令行长度限制可通过如下命令查看:
# linux通过ARG_MAX参数控制命令行参数的长度,在ubuntu上查询结果为2097152个字符 getconf ARG_MAX
-
-
简单的命令参数使用Abseil比较方便,如果涉及复杂的命令行参数,比如复杂的对象数据,二进制数据等可能有点困难。
以上情况,通过命令行传递配置文件,解析配置文件来传递信息是更好的一个选择。
常规使用
-
标志使用
最好在main()函数的文件中定义标志,并在该文件中读取标志。 封装一个模块,解析参数并转化写入进程内部的配置对象的方式更好。当然如果是简单的测试程序,在main函数中读取就可以。
-
标志定义,解析及读取
标志的使用包括几部分:
-
定义
通过**ABSL_FLAG(Type, name, default_value, help)**方式定义标志。
支持的类型有:
bool
int16_t
uint16_t
int32_t
uint32_t
int64_t
uint64_t
float
double
std::string
std::vector<std::string>
std::optional<T>
(see “Optional Flags” below)absl::LogSeverity
(provided natively for layering reasons)absl::Duration
absl::Time
-
解析
在main函数开头调用std::vector<char*> ParseCommandLine(int argc, char* argv[])函数解析标志,未解析的返回到vector数组中。
-
读取
通过absl::GetFlag(FLAGS_firstname)读取标志值,其中firstname为定义的标志名称。
#include "absl/flags/parse.h" #include "absl/flags/flag.h" #include "absl/strings/str_join.h" #include <iostream> // 标志定义 // 参数1: 标志类型 // 参数2: 标志明 // 参数3: 默认值 // 参数4: 标志描述 ABSL_FLAG(bool, big_menu, true, "Include 'advanced' options in the menu listing"); // 字符串标志,并std::optional解决是否有标志输入,如果使用c++14,可使用absl的optional ABSL_FLAG(std::optional<std::string>, image_file, std::nullopt, "Sets the image input from a file."); // 字符串标志 ABSL_FLAG(std::vector<std::string>, languages, std::vector<std::string>({"english", "french", "german"}), "comma-separated list of languages to offer in the 'lang' menu"); int main(int argc, char *argv[]) { // 标志解析 auto posArgv = absl::ParseCommandLine(argc, argv); // 读取未解析的参数,按位置打印 std::cout << "pos argv:" << absl::StrJoin(posArgv, " ") << std::endl; // 读取bool串类型标志 std::cout << "flag big_menu:" << absl::GetFlag(FLAGS_big_menu) << std::endl; // 读取字符串标志 auto imageFile = absl::GetFlag(FLAGS_image_file); if (imageFile.has_value()) { std::cout << "flag image_file:" << imageFile.value() << std::endl; } // 读取字符串数组 std::cout << "flag languages:" << absl::StrJoin(absl::GetFlag(FLAGS_languages), " ") << std::endl; }
输出: .
-
-
判断标志是否输入
有时候需要判断标志的参数是否有输入,如果未输入需要做特定的处理。比如一个uint16_t的标志,默认值为0,这时可能不能判断其是否是有效输入。这个时候需要使用std::optional类型的标志,如果使用的C++14,可使用absl::optional(头文件:“absl/types/optional.h”)
-
参数使用方式提示
在ParseCommandLine前调用SetProgramUsageMessage设置使用方式提示。通过–helpfull可参看使用方式提示,并能看到定义的标志说明。
代码:
#include "absl/flags/parse.h" #include "absl/flags/flag.h" #include "absl/flags/usage.h" #include "absl/strings/str_join.h" #include "absl/strings/str_cat.h" #include <iostream> // 参数1: 标志类型 // 参数2: 标志明 // 参数3: 默认值 // 参数4: 标志描述 ABSL_FLAG(bool, big_menu, true, "Include 'advanced' options in the menu listing"); void readFlagTest() { // 打印bool串类型标志 std::cout << "flag big_menu:" << absl::GetFlag(FLAGS_big_menu) << std::endl; } int main(int argc, char *argv[]) { // 设置使用方式 absl::SetProgramUsageMessage(absl::StrCat("This program does nothing. Sample usage:\n", argv[0], " big_menu=false")); // 解析参数 auto posArgv = absl::ParseCommandLine(argc, argv); // 打印未解析的参数,按位置打印 std::cout << "pos argv:" << absl::StrJoin(posArgv, " ") << std::endl; readFlagTest(); }
输出:
-
注意事项:
-
SetProgramUsageMessage不能调用2此,会引起崩溃。
-
输入未定义的参数,程序将退出。
比如未定义-filename。命令行输入参数-filename=book.txt,程序将退出。所以在删除参数是需要注意,防止出现版本不匹配的进程退出的情况。
同时可以在命令行末尾加上–undefon="filename"来表示在程序中未定义该标志也可以正常解析。
-