在C ++中解析命令行参数的有效方法是什么?

What's an effective way to parse command line parameters in C++?

在C++中有一种处理命令行参数的有效方法吗?

我在下面所做的感觉完全不专业,我无法想象这是如何在专业软件中处理命令行参数(ATOI,硬编码的argc检查)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Command line usage: sum num1 num2

int main(int argc, char *argv[])
{
&nbsp;&nbsp;&nbsp;if (argc < 3)
&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout <<"Usage:" << argv[0] <<" num1 num2
"
;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit(1);
&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;int a = atoi(argv[1]);
&nbsp;&nbsp;&nbsp;int b = atoi(argv[2]);
&nbsp;&nbsp;&nbsp;int sum = a + b;
&nbsp;&nbsp;&nbsp;cout <<"Sum:" << sum <<"
"
;
&nbsp;&nbsp;&nbsp;return 0;
}


您可能需要使用外部库来实现这一点。有许多可供选择。

Boost有一个功能丰富(和往常一样)的库Boost程序选项。

在过去的几年里,我个人最喜欢的是TCLAP——纯粹是模板化的,因此没有库或链接、自动化的"帮助"生成和其他功能。请参阅文档中最简单的示例。


您可以为此使用已经创建的库

http://www.boost.org/doc/libs/1_44_0/doc/html/program_options.html


如果这是Linux/Unix,那么使用的标准配置是gnu getopt

http://www.gnu.org/s/libc/manual/html_node/getopt.html


它太大了,无法包含在堆栈溢出应答中,但我创建了一个用于声明性定义命令行的库。它利用C++ 14的能力,通过给每个成员变量提供初始值来构造类构造函数。

图书馆主要是一个基类。若要定义命令语法,请声明从其派生的结构。这是一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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;

ArgumentOptionAlias类模板在CommandLine基类的范围内声明,您可以将它们专门用于您自己的类型。每一个都接受this指针、选项名、默认值和用于打印命令摘要/用法的说明。

我仍在寻求消除在里面撒上所有this指针的需要,但我还没有找到一种不引入宏的方法。这些指针允许每个成员向驱动解析的基类中的表注册自己。

一旦您有了一个实例,就有几个方法重载来解析来自字符串或main样式参数向量的输入。分析器处理Windows样式和Unix样式选项语法。

1
2
3
4
5
6
7
8
9
if (!cl.Parse(argc, argv)) {
    std::string message;
    for (const auto &error : cl.GetErrors()) {
        message += error +"
"
;
    }
    std::cerr << message;
    exit(EXIT_FAILURE);
}

解析后,可以使用operator()访问任何选项的值:

1
2
if (cl.m_help()) { std::cout << cl.GetUsage(); }
for (int i = 0; i < cl.m_loops(); ++i) { ... }

整个图书馆只有大约300行(不包括测试)。实例有点膨胀,因为解析表是实例的一部分(而不是类)。但是,通常每个程序只需要一个实例,这种纯声明性方法的便利性非常强,可以通过解析新的输入来重置实例。


我在windows/mingw下使用getopt():

1
2
3
4
5
6
7
8
9
10
11
while ((c = getopt(myargc, myargv,"vp:d:rcx")) != -1) {
        switch (c) {
        case 'v': // print version
            printf("%s Version %s
"
, myargv[0], VERSION);
            exit(0);
            break;
        case 'p': // change local port to listen to
            strncpy(g_portnum, optarg, 10);
            break;
...

我建议使用Boostlexical_cast<>来代替垃圾,如atoiatof等。

http://www.boost.org/doc/libs/release/libs/conversion/lexical_cast.htm

除此之外,你的代码可以用于简单的事情。