在C ++中有没有一种真正有效的处理命令行参数的方法?
我在下面做的事情完全是业余的,我无法想象这是如何在专业软件中真正处理命令行参数(atoi,硬编码的argc检查)。
// Command line usage: sum num1 num2 int main(int argc, char *argv[]) { if (argc < 3) { cout << "Usage: " << argv[0] << " num1 num2\n"; exit(1); }
int a = atoi(argv[1]); int b = atoi(argv[2]); int sum = a + b;
cout << "Sum: " << sum << "\n";
return 0; }
答案 0 :(得分:18)
您可能想要使用外部库。有许多可供选择。
Boost有一个功能丰富的(通常)库Boost Program Options。
我个人最近几年的最爱是TCLAP - 纯粹模板化,因此没有图书馆或链接,自动' - help'代和其他好东西。请参阅文档中的simplest example。
答案 1 :(得分:3)
答案 2 :(得分:2)
如果这是linux / unix,那么使用的标准是gnu getopt
答案 3 :(得分:1)
它有点太大而无法包含在Stack Overflow答案中,但是我创建了一个用于以声明方式定义命令行的库。它利用C ++ 14的能力,通过为每个成员变量提供初始值来构建类构造函数。
该库主要是基类。要定义命令语法,请声明从中派生的结构。这是一个样本:
struct MyCommandLine : public core::CommandLine {
Argument<std::string> m_verb{this, "program", "program.exe",
"this is what my program does"};
Option<bool> m_help{this, "help", false,
"displays information about the command line"};
Alias<bool> alias_help{this, '?', &m_help};
Option<bool> m_demo{this, "demo", false,
"runs my program in demonstration mode"};
Option<bool> m_maximize{this, "maximize", false,
"opens the main window maximized"};
Option<int> m_loops{this, "loops", 1,
"specifies the number of times to repeat"};
EnumOption<int> m_size{this, "size", 3,
{ {"s", 1},
{"small", 1},
{"m", 3},
{"med", 3},
{"medium", 3},
{"l", 5},
{"large", 5} } };
BeginOptionalArguments here{this};
Argument<std::string> m_file{this, "file-name", "",
"name of an existing file to open"};
} cl;
Argument
,Option
和Alias
类模板在CommandLine
基类的范围内声明,您可以将它们专门用于您自己的类型。每个都采用this
指针,选项名称,默认值和描述,用于打印命令概要/用法。
我仍然希望消除在那里撒上所有this
指针的需要,但我还没有找到一种方法来实现它而不引入宏。这些指针允许每个成员将自己注册到驱动解析的基类中的表。
一旦有了实例,就会有一些方法重载来解析字符串或main
- 样式参数向量的输入。解析器处理Windows样式和Unix样式的选项语法。
if (!cl.Parse(argc, argv)) {
std::string message;
for (const auto &error : cl.GetErrors()) {
message += error + "\n";
}
std::cerr << message;
exit(EXIT_FAILURE);
}
解析后,您可以使用operator()
访问任何选项的值:
if (cl.m_help()) { std::cout << cl.GetUsage(); }
for (int i = 0; i < cl.m_loops(); ++i) { ... }
整个图书馆只有大约300行(不包括测试版)。实例有点臃肿,因为解析表是实例的一部分(而不是类)。但是你通常每个程序只需要一个实例,这种纯粹声明性方法的便利性非常强大,只需解析新输入即可重置实例。
答案 4 :(得分:0)
我建议始终使用提升lexical_cast<>
代替atoi
,atof
等垃圾。
http://www.boost.org/doc/libs/release/libs/conversion/lexical_cast.htm
除了你的代码还可以用于简单的东西。
答案 5 :(得分:0)
我在windows / mingw下使用getopt():
while ((c = getopt(myargc, myargv, "vp:d:rcx")) != -1) {
switch (c) {
case 'v': // print version
printf("%s Version %s\n", myargv[0], VERSION);
exit(0);
break;
case 'p': // change local port to listen to
strncpy(g_portnum, optarg, 10);
break;
...