Abseil系列四:flags(命令行解析访问库)使用

简介

Abseil标志库允许对通过命令行传递给可执行程序的标志值进行编程访问。其实就是对命令行参数进行解析,并可快速访问的一个工具库。

Abseil Flags库提供了以下特性:

  • 以线程安全的方式访问Abseil标志

  • 在程序生命周期的任何点都可以访问有效的标志值

  • 确保同一进程内的唯一性,防止标志名称冲突

  • 提供内置的用法提供的关联帮助文本

  • 支持布尔型、整型和字符串类型等,并可扩展以支持其他Abseil类型和自定义类型

  • 支持默认值,并可对标志值的进行读写

  • 允许在不同地方声明和定义标志,尽管这种用法有缺点,通常应该避免。

标志的值由absl:: parsecommanline()从命令行解析。 每个标志的结果值存储在一个未指定类型的全局变量absl:: flag 中。

flags库的介绍和使用详见官网:flags

限制

  • 因命令行参数的长度是有限制的,根据各系统定义不一致。因此对输入参数较长的慎用该方式。

    • windows命令行最大长度为 8191 个字符,详细介绍见:命令行字符串限制

    • linux命令行长度限制可通过如下命令查看:

      # linux通过ARG_MAX参数控制命令行参数的长度,在ubuntu上查询结果为2097152个字符
      getconf ARG_MAX
      
  • 简单的命令参数使用Abseil比较方便,如果涉及复杂的命令行参数,比如复杂的对象数据,二进制数据等可能有点困难。

以上情况,通过命令行传递配置文件,解析配置文件来传递信息是更好的一个选择。

常规使用

  1. 标志使用

    最好在main()函数的文件中定义标志,并在该文件中读取标志。 封装一个模块,解析参数并转化写入进程内部的配置对象的方式更好。当然如果是简单的测试程序,在main函数中读取就可以。

  2. 标志定义,解析及读取

    标志的使用包括几部分:

    • 定义

      通过**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;
    }
    
    

    输出: .在这里插入图片描述

  3. 判断标志是否输入

    有时候需要判断标志的参数是否有输入,如果未输入需要做特定的处理。比如一个uint16_t的标志,默认值为0,这时可能不能判断其是否是有效输入。这个时候需要使用std::optional类型的标志,如果使用的C++14,可使用absl::optional(头文件:“absl/types/optional.h”)

  4. 参数使用方式提示

    在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();
    }
    
    

    输出: 在这里插入图片描述

  5. 注意事项:

    • SetProgramUsageMessage不能调用2此,会引起崩溃。

    • 输入未定义的参数,程序将退出。

      比如未定义-filename。命令行输入参数-filename=book.txt,程序将退出。所以在删除参数是需要注意,防止出现版本不匹配的进程退出的情况。

      同时可以在命令行末尾加上–undefon="filename"来表示在程序中未定义该标志也可以正常解析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaobaiPlayGame

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值