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

时间:2010-09-30 00:32:02

标签: c++ command-line-arguments

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

6 个答案:

答案 0 :(得分:18)

您可能想要使用外部库。有许多可供选择。

Boost有一个功能丰富的(通常)库Boost Program Options

我个人最近几年的最爱是TCLAP - 纯粹模板化,因此没有图书馆或链接,自动' - help'代和其他好东西。请参阅文档中的simplest example

答案 1 :(得分:3)

答案 2 :(得分:2)

如果这是linux / unix,那么使用的标准是gnu getopt

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

答案 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;

ArgumentOptionAlias类模板在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<>代替atoiatof等垃圾。

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;
...