一、什么是gflags?

gflags 是一个由 Google 开发的命令行参数解析库,主要用于在 C++(也支持其他语言)程序中便捷地处理命令行参数。它的核心作用是帮助开发者快速定义、解析和使用命令行选项,避免手动编写繁琐的参数解析逻辑。

比如你写了个聊天软件,我们指定 “端口 = 8080” 。但总有用户会和我们的口味不一样,用户运行时可能指定“端口 = 9090,8888,8989…”,这时我们总不能根据每个用户的端口号一个一个去判断吧

有了 gflags,你只需用它的宏定义:

DEFINE_int32(port, 8080, "端口号");  // 定义端口参数,默认8080

然后调用一句解析函数,用户输入的 “–port=9000” 就会通过命令行对应到变量里,这时运行函数,宏定义的port就是9000,我们只需在终端就能改变程序参数值。(再次运行就会变成默认值。还能自动生成–help帮助信息,用户输入程序名–help就知道能传哪些参数。)

二、Linux 下安装 gflags

gflags 安装非常简单,支持 包管理器安装 和 源码编译安装 两种方式,根据需求选择即可。

1. 包管理器安装)

Ubuntu/Debian 系列:

sudo apt update && sudo apt install -y libgflags-dev

CentOS/RHEL 系列:

sudo yum install -y gflags-devel

安装完成后,头文件默认位于 /usr/include/gflags/,库文件位于/usr/lib/x86_64-linux-gnu/(Ubuntu)或 /usr/lib64/(CentOS)。

2. 源码编译安装

如果需要使用 gflags 的最新特性(如自定义参数别名、配置文件读取增强),可从 GitHub 源码编译:

# 下载源码 
git clone https://github.com/gflags/gflags.git 
# 切换目录 
cd gflags/
mkdir build 
cd build/ 
# 生成Makefile 
cmake .. 
# 编译代码 
make 
# 安装 
make install

编译完成后,头文件和库文件会被安装到 /usr/local 目录下。

三、实例

理论不如实践,我们从一个最简单的程序入手,感受 gflags 的核心用法。这个程序将解析 3 个常用参数:调试模式(布尔值)、服务端口(整数)、日志路径(字符串)。

1. 编写代码

#include <iostream>
#include <gflags/gflags.h> DEFINE_bool(debug, false, "检查程序是否正常启动");
DEFINE_int32(port, 8080, "查看服务端端口号");
DEFINE_string(log_path, "./log", "查看当前日志路径");int main(int argc, char** argv) {// 解析命令行参数:必须在使用参数前调用// 第三个参数为 true 表示解析后移除参数,argv 仅保留程序名和非参数参数gflags::ParseCommandLineFlags(&argc, &argv, true);std::cout << "debug: " << (FLAGS_debug ? "ON" : "OFF") << std::endl;std::cout << "port: " << FLAGS_port << std::endl;std::cout << "log_path: " << FLAGS_log_path << std::endl;return 0;
}

2. 编译与运行

编译时需要链接 gflags 库(使用 -lgflags 选项):

g++ -o main main.cc -lgflags

运行程序并传入参数,感受 gflags 的解析效果:

在这里插入图片描述

3. 核心逻辑解析

  • 参数定义:通过 DEFINE_<类型> 宏声明参数,无需手动写解析逻辑。例如 DEFINE_bool(debug, false, “…”) 声明了一个名为 debug 的布尔参数,默认值 false,帮助说明为括号内的字符串。
  • 参数解析:gflags::ParseCommandLineFlags(&argc, &argv, true) 是核心函数,负责解析命令行参数并填充到 FLAGS_<参数名> 变量中。
  • 参数访问:直接通过 FLAGS_<参数名> 访问解析后的值,类型与定义时一致(如 FLAGS_port 是 int32_t 类型)。

四、gflags特性及使用

掌握了基础用法后,我们来深入了解 gflags 的几个实用特性,让参数解析更灵活。

1. 支持的参数类型

gflags 提供了 6 种常用类型的参数宏,覆盖大部分开发场景:

宏定义类型用途示例
DEFINE_boolbool启用 / 禁用功能(–debug)
DEFINE_int32int32_t32 位整数(–port=8080)
DEFINE_int64int64_t64 位整数(–max_conn=1000000)
DEFINE_uint64uint64_t无符号 64 位整数(–timeout=3600)
DEFINE_doubledouble浮点数(–threshold=0.95)
DEFINE_stringstd::string字符串(–log_path=/var/log)

2. 参数验证:避免非法输入

实际开发中,参数往往有合法范围(如端口号必须在 1-65535 之间)。gflags 支持通过 DEFINE_validator 宏为参数绑定验证函数,自动拦截非法输入。
示例:为端口参数添加验证
在之前的代码中添加以下内容:

// 验证函数:参数名(flagname)、参数值(value),返回 bool 表示是否合法
static bool ValidatePort(const char* flagname, int32_t value) {if (value > 0 && value < 65536) {  // 端口号合法范围return true;}// 非法时输出错误信息std::cerr << "Invalid value for --" << flagname << ": " << value << " (must be 1-65535)" << std::endl;return false;
}// 为 port 参数绑定验证函数
DEFINE_validator(port, &ValidatePort);  // 格式:DEFINE_validator(参数名, 验证函数)

测试非法参数:

./gflags_demo --port=70000  # 端口 70000 超出范围
Invalid value for --port: 70000 (must be 1-65535)

3. 从配置文件读取参数

gflags 支持从文件读取参数,不用每次在命令行输入一堆参数,特别方便。
先建个参数文件(比如叫 config.txt),里面写参数(不用加 --):

-port=9000
-debug=true
-log_path=/var/log

运行程序时,用 --flagfile 指定这个文件:

./main --flagfile=config.txt

在这里插入图片描述

4. 自动生成帮助信息

gflags 会自动为所有参数生成 --help 帮助信息,无需手动编写。运行程序时添加 --help 即可查看:

./main --help

输出帮助信息:
在这里插入图片描述

可以看到,gflags 不仅显示了我们自定义的参数,还自带了 --helpfull(详细帮助)、–version(版本信息)等通用参数。

五、常见问题

1. 编译时提示 “找不到 gflags 库”?

如果使用源码编译安装 gflags,可能会出现链接器找不到库文件的问题。解决方法:
编译时指定库路径:

g++ -o demo demo.cpp -lgflags -L/usr/local/lib

若仍报错,执行 sudo ldconfig 更新系统库缓存(让系统识别新安装的 gflags 库)。

2. 布尔参数的特殊用法

布尔参数支持三种写法,效果相同:

./gflags_demo --debug        # 启用(相当于 --debug=true)
./gflags_demo --nodebug      # 禁用(相当于 --debug=false)
./gflags_demo --debug=false  # 显式指定 false

3.小技巧

  • 参数命名:使用全小写 + 下划线(如 log_path),符合命令行参数习惯。
  • 默认值合理性:为参数设置安全的默认值(如端口默认 8080,避免与系统端口冲突)。
  • 必选参数处理:gflags 不直接支持 “必选参数”,可在解析后手动检查,例如:
if (FLAGS_log_path.empty()) {std::cerr << "Error: --log_path is required!" << std::endl;return 1;
}
  • 版本信息设置:通过 gflags::SetVersionString(“1.0.0”) 设置版本,配合 --version 参数使用:
int main(int argc, char** argv) {gflags::SetVersionString("1.0.0");  // 设置版本号gflags::SetUsageMessage("Usage: ./gflags_demo [options]");  // 设置用法提示gflags::ParseCommandLineFlags(&argc, &argv, true);// ...
}

最后,附上 gflags 官方仓库地址,以便获取最新版本和更多细节:gflags GitHub 仓库

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96594.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96594.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/96594.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

编译器的前端中端和后端

前面说的词法分析和语法分析&#xff0c;确实是编译器前端 (Front End) 最核心的两个部分。但前端的工作还没有结束。编译器各阶段划分 一个完整的编译器通常可以分为三个部分&#xff1a;前端、中端 (Middle End)、后端 (Back End)。 前端 (Front End) 核心职责: 理解源代码。…

黑马Java进阶教程,全面剖析Java多线程编程,并发和并行,笔记02

黑马Java进阶教程&#xff0c;全面剖析Java多线程编程&#xff0c;并发和并行&#xff0c;笔记02 一、并发和并行 并发&#xff1a;在同一时刻&#xff0c;有多个指令在单个CPU上交替执行 并行&#xff1a;在同一时刻&#xff0c;有多个指令在多个CPU上同时执行 二、为什么有…

20250908 背包DP总结

引子 ~ 我们都有一个家&#xff0c;名字叫背包 ~ 背包DP 顾名思义&#xff0c;背包DP是用来解决背包最值问题的。题目会给出背包的容量&#xff0c;以及几个物品的属性&#xff0c;比如重量&#xff0c;价值&#xff0c;限额等等&#xff0c;具体是什么看题目。 01背包 01…

Redis持久化之RDB:快照机制原理、配置与最佳实践

Redis持久化之RDB&#xff1a;快照机制原理、配置与最佳实践 1. RDB持久化概述 1.1 什么是RDB RDB&#xff08;Redis Database&#xff09;是Redis的默认持久化方式&#xff0c;它在指定的时间间隔内生成数据集的快照&#xff08;snapshot&#xff09;&#xff0c;并将快照保…

daily notes[44]

文章目录基础references基础 hello,world是几乎所有编程语言的第一例子&#xff0c;rust也不例外。但和其它语言不一样&#xff0c;Rust的源码最好拥有自己的项目目录。 $ mkdir ~/pro $ cd ~/pro $ mkdir helloWorld $ cd helloWorld源代码文件名为main.rs&#xff0c;内容如…

JavaScript对象创建方式完全指南:从原始到现代的演进之路

前言 作为一名前端开发者&#xff0c;JavaScript中对象创建是很重要。在JavaScript这门基于原型的语言中&#xff0c;对象几乎无处不在。今天&#xff0c;我将带领大家回顾JavaScript对象创建的7种方式&#xff0c;从最原始的字面量到现代的ES6 class&#xff0c;每一步演进都解…

基于单片机的无线水塔监控系统设计(论文+源码)

本设计为基于单片机的无线水塔监控系统设计&#xff0c;主要由以下几部分组成&#xff1a;均采用STC89C52RC单片机为主控&#xff1b;主机&#xff1a;NRF24L01无线通讯模块&#xff0c;1602LCD液晶显示屏。从机&#xff1a;NRF24L01无线通讯模块&#xff0c;水位传感器&#x…

凌晨0-3点不睡,你熬的不是夜,是人生!

“熬夜”这个词&#xff0c;早已成为现代生活的常态。有人为了工作加班到深夜&#xff0c;有人为了娱乐刷剧到天明&#xff0c;但你知道吗&#xff1f;熬夜最“要命”的时间段&#xff0c;其实是凌晨0点到凌晨3点。别以为只是少睡几个小时而已&#xff0c;这个时间段不睡&#…

大语言模型基石:Transformer

一、引言 如今火爆的 GPT、LLaMA、通义千问、ChatGLM 等大语言模型&#xff0c;背后都离不开一个核心架构——Transformer。 2017 年&#xff0c;Google 在论文《Attention Is All You Need》中首次提出 Transformer 模型&#xff0c;彻底改变了自然语言处理的发展方向。它摒…

【算法】【链表】160.相交链表--通俗讲解

算法通俗讲解推荐阅读 【算法–链表】83.删除排序链表中的重复元素–通俗讲解 【算法–链表】删除排序链表中的重复元素 II–通俗讲解 【算法–链表】86.分割链表–通俗讲解 【算法】92.翻转链表Ⅱ–通俗讲解 【算法–链表】109.有序链表转换二叉搜索树–通俗讲解 【算法–链表…

MySQL——库的操作

1、创建数据库语法&#xff1a;CREATE DATABASE [IF NOT EXISTS] db_name [create_specification [, create_specification] ...] create_specification: [DEFAULT] CHARACTER SET charset_name [DEFAULT] COLLATE collation_name这里的CHARACTER SET表示指定数据库采用的字符集…

Python ast模块(Abstract Syntax Trees,抽象语法树)介绍及使用

文章目录 核心概念 基本使用流程 常用节点类型 示例代码 实际应用场景 注意事项 `ast.literal_eval()` 功能说明 适用场景 使用示例 限制与安全特性 与 `eval()` 的对比 总结 Python 的 ast 模块( Abstract Syntax Trees,抽象语法树)允许你解析、分析和修改 Python 代码的…

C++宽度优先搜索算法:队列与优先级队列

本期我们就来深入学习一下C算法中一个很重要的算法思想&#xff1a;宽度优先搜索算法 宽度优先算法是一个应用十分广泛的算法思想&#xff0c;涉及的领域也十分繁多&#xff0c;因此本篇我们先只涉猎它的一部分算法题&#xff1a;队列/优先级队列&#xff0c;后续我们会进一步地…

类的property属性

​​Python 中的 property 特性详解​​property 是 Python 中用于​​将方法转换为属性​​的装饰器&#xff0c;它允许开发者以访问属性的方式调用方法&#xff0c;同时可以添加逻辑控制&#xff08;如数据校验、计算属性等&#xff09;。以下是其核心用法和优势&#xff1a;…

【Redis#9】其他数据结构

引言 Redis 除了我们最常用的 String、Hash、List、Set、ZSet&#xff08;Sorted Set&#xff09; 这五种基本数据结构外&#xff0c;还提供了很多高级或特殊用途的数据结构/类型 &#xff0c;它们可以满足更复杂的业务需求。 ✅ Redis 的“五大基本数据结构”回顾类型特点Stri…

AutoGen——自定义Agent

目录引子自定义 AgentCountDownAgentArithmeticAgent在自定义 Agent 中使用自定义模型客户端让自定义 Agent 声明式化Selector Group Chat示例&#xff1a;网页搜索 / 数据分析代理&#xff08;Agents&#xff09;Workflow终止条件&#xff08;Termination Conditions&#xff…

【重定向和转发的核心理解】

重定向和转发 不废话&#xff1a; “转发” 的核心定义&#xff1a; 服务端内部主导跳转、客户端无感知&#xff08;仅 1 次请求&#xff09;、浏览器 URL 不改变&#xff0c;与传统 Web 开发中 “转发” 的本质逻辑完全一致&#xff0c;只是实现载体&#xff08;Nginx 路由层 …

生成对抗网络详解与实现

生成对抗网络详解与实现0. 前言1. GAN 原理2. GAN 架构3. 损失函数3.1 判别器损失3.2 生成器损失3.4 VANILLA GAN4. GAN 训练步骤0. 前言 生成对抗网络 (Generative Adversarial Network, GAN) 是图像和视频生成中的主要方法之一。在本节中&#xff0c;我们将了解 GAN 的架构、…

FPGA硬件开发-XPE工具的使用

目录 XPE 工具概述​ XPE 使用步骤详解​ 1. 工具获取与初始化​ 2. 器件选择与配置​ 3. 电源电压设置​ 4. 资源使用量配置​ 5. 时钟与开关活动配置​ 6. 功耗计算与报告生成​ 报告解读与电源设计优化​ 常见问题与最佳实践​ 与实际功耗的差异处理​ 工具版本…