☰
arg_parser,一个轻量的 C++17 单头文件命令行参数解析库
2026/10/5 6:59:47 网站建设 项目流程

给 C++ 小工具添加命令行参数时,很容易从几个argv判断开始,逐渐写出一串处理短参数、默认值、类型转换和错误提示的代码。参数多起来以后,帮助信息也要跟着手动维护。

arg_parser把这些常用操作整理成一个小型库:注册参数,调用parse(),再通过get<T>()读取结果。项目只需要一个头文件,适合给文件处理工具、命令行程序和个人项目添加基础的参数解析能力。

项目地址:KAI-SHUNG/arg_parser。

有哪些功能?

  • 单头文件、无第三方依赖:使用 C++17,把arg_parser.hpp放进项目即可,不需要额外编译库文件。

  • 三类参数:支持无值开关、带值选项和位置参数,也支持短别名。

  • 参数配置与类型获取:支持默认值、必填参数、描述,以及get<std::string>()、get<int>()等读取方式。

  • 内置帮助输出:根据注册信息生成用法和参数说明,应用可以用它处理-h、--help。

  • Windows Unicode 输入:支持从wmain接收 UTF-16 参数,并转换为 UTF-8。

例如,下面几种输入都可以解析:

./demo photo.png -o result.txt -c 120 -v ./demo "my photo.png" --output=result.txt --count=120 ./demo --count=-12 ./demo -h

如何接入项目?

可以先克隆仓库:

git clone https://github.com/KAI-SHUNG/arg_parser.git cd arg_parser

然后把arg_parser.hpp复制到自己的源码目录或头文件搜索目录,在代码中包含它:

#include "arg_parser.hpp"

编译器需要支持 C++17。下面的完整示例可以直接保存为demo.cpp,与头文件放在同一目录。

一个完整可运行的例子

这个示例接收输入文件名、输出文件名、一个整数和一个布尔开关。它只打印解析结果,用来展示接口,不执行实际的文件处理。

#include "arg_parser.hpp" #include <iostream> ​ #ifdef _WIN32 int wmain(int argc, wchar_t* argv[]) #else int main(int argc, char* argv[]) #endif { using arg_parser::ArgType; arg_parser::ArgParser parser; parser.set_program_name("demo"); ​ parser.add_argument("input") .set_default("input.png").set_description("Input file"); parser.add_argument("output", "o", ArgType::Option) .set_default("output.txt").set_description("Output file"); parser.add_argument("count", "c", ArgType::Option) .set_default("80").set_description("Count value"); parser.add_argument("verbose", "v", ArgType::Flag) .set_default("false").set_description("Enable verbose mode"); parser.add_argument("help", "h", ArgType::Flag) .set_description("Show help"); ​ try { parser.parse(argc, argv); if (parser.has("help")) { parser.help(); return 0; } ​ std::cout << "input=" << parser.get<std::string>("input") << '\n' << "output=" << parser.get<std::string>("output") << '\n' << "count=" << parser.get<int>("count") << '\n' << "verbose=" << parser.get<bool>("verbose") << '\n'; } catch (const std::exception& error) { std::cerr << error.what() << '\n'; parser.help(); return 1; } return 0; }

在 Linux、macOS 等使用main的环境中,可以这样编译运行:

g++ -std=c++17 demo.cpp -o demo ./demo photo.png -o result.txt -c 120 -v

Windows 使用 MinGW 编译上述wmain版本时,需要加上-municode:

g++ -std=c++17 -municode demo.cpp -o demo.exe ./demo.exe photo.png -o result.txt -c 120 -v

输出如下:

input=photo.png output=result.txt count=120 verbose=1

没有传入参数时,会使用示例中配置的默认值:input.png、output.txt、80和false。这里没有启用std::boolalpha,因此布尔值打印为0或1。

仓库也提供了较短的 example.cpp,可以直接克隆后编译运行。

三类参数分别怎么用?

注册接口是:

add_argument(name, alias = std::nullopt, type = ArgType::Positional)

name是正式名称,alias是可选别名,两者都不带前导-。名称和别名不能与已经注册的参数冲突。默认类型是位置参数,返回的Argument&可以继续链式调用配置函数。

类型注册示例命令行输入用途
Positionaladd_argument("input")photo.png按注册顺序接收位置参数
Optionadd_argument("output", "o", ArgType::Option)--output result.txt或-o=result.txt接收一个值
Flagadd_argument("verbose", "v", ArgType::Flag)--verbose或-v表示开关,提供时保存为"true"

带值选项支持这四种形式:

./demo --output=result.txt ./demo --output result.txt ./demo -o=result.txt ./demo -o result.txt

位置参数默认也不是必填。需要用户明确提供时,要单独设置set_required(true)。

默认值、必填参数与类型转换

默认值使用字符串配置,读取时再转换为目标类型。例如,完整示例已经为count配置了.set_default("80"),解析后可以这样读取:

int count = parser.get<int>("count");

如果用户省略count,get<int>("count")会返回默认值80。如果传入--count=12abc,读取整数时会抛出异常,不会只取前面的12。字符串读取会保留空格;例如"my photo.png"会作为一个完整的文件名返回。

对于必须显式传入的选项,可以在调用parse()前注册:

parser.add_argument("config", std::nullopt, ArgType::Option) .set_required(true) .set_description("Configuration file");

此时需要提供--config settings.json。即使这个参数设置了默认值,也不能代替用户的显式输入。

get<bool>()当前按字符串是否等于"true"返回结果。因此,开关参数通常搭配.set_default("false")使用;不要把它当作支持任意布尔字面量的转换器。

has()和get<T>()有什么区别?

has()判断的是“用户是否明确提供了这个参数”,默认值不算明确提供。它支持正式名称和别名,例如has("output")与has("o")。

get<T>()则读取参数值:用户提供了就读取输入,没提供就尝试默认值。读取时应使用正式名称,例如get<std::string>("output"),不要使用别名"o"。

两者配合,适合区分“用户主动设置”与“使用程序默认配置”:

if (parser.has("output")) { std::cout << "Output was explicitly provided\n"; } std::string output = parser.get<std::string>("output");

这些读取操作都应放在parse()之后。

帮助信息不用单独维护

运行:

./demo -h

会得到上面完整示例生成的帮助信息:

Usage: demo [options] <input> Options: --input Input file --output, -o <value> Output file --count, -c <value> Count value --verbose, -v Enable verbose mode --help, -h Show help

参数名称、别名和描述都来自注册信息。set_program_name()可以设置用法中的程序名,set_note()可以在帮助末尾追加说明。

注意:注册一个叫help的参数不会自动显示帮助。应用需要在解析后检查它,再调用help(),完整示例已经展示了这一流程。

Windows 中文参数怎么处理?

头文件在 Windows 上提供parse(argc, wchar_t** argv)重载,可以与wmain配合,把 UTF-16 参数转换为 UTF-8。对于中文文件名等非 ASCII 参数,这能保留输入内容,例如:

./demo.exe "图片.png" --output="结果.txt"

get<std::string>()得到的是 UTF-8 字符串。后续如果把它交给文件操作接口,还需要确认该接口接受的编码;终端显示效果也取决于终端配置。

一些需要了解的边界

这个项目的接口集中在基础参数解析。使用时需要注意以下约定:

  • 负数和以-开头的选项值使用=:例如--count=-12、--output=-result.txt。--count -12会被视为缺少值。

  • 以-开头的位置参数使用--分隔:例如./demo -- -photo.png,分隔符后的内容按位置参数处理。

  • 不支持短开关合并:用-v -h,不要写成-vh。

  • 位置参数仍按顺序传入:帮助输出目前会把input列在Options中,但实际应写./demo photo.png,不能用--input=photo.png。

  • 同一个开关或选项不能重复提供:例如--output=a.txt -o=b.txt会被拒绝。

  • 每个解析器实例只调用一次parse():需要解析另一组输入时,新建实例。

  • 必填检查先于应用的帮助处理:如果添加了必填参数,仅传-h仍可能在parse()中触发缺少必填参数的异常。需要自行安排错误与帮助的展示流程;完整示例会在捕获异常后显示帮助。

未知参数、缺少选项值、重复输入和必填参数缺失会在解析时报告;数值转换错误会在调用get<T>()时报告。实际应用中,建议像完整示例一样捕获异常并给出错误提示。

如何运行项目测试?

仓库包含参数解析、别名、默认值、必填检查、类型转换、帮助输出和 Unicode 输入等测试。可以在仓库根目录编译运行:

g++ -std=c++17 -I. tests/test_arg_parser.cpp -o test_arg_parser ./test_arg_parser

Windows 下把输出文件名改成test_arg_parser.exe,并运行./test_arg_parser.exe。测试程序使用普通main,不需要-municode。

项目地址与许可证

项目采用 MIT 许可证,完整源码、接口说明和示例都在仓库中:

  • GitHub 仓库

  • 单头文件 arg_parser.hpp

  • README 与 API 说明

如果你正在给一个 C++ 小工具添加命令行入口,可以从这个单头文件开始试用。欢迎通过 Issues 反馈使用问题,也欢迎提交改进。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询