首页 文章

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

提问于
浏览
5

有没有一种真正有效的方法来处理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

    您可能想要使用外部库 . 有很多可供选择 .

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

    我个人最近几年的最爱是TCLAP - 纯模板化,因此没有库或链接,自动生成和其他好东西 . 请参阅文档中的simplest example .

  • 18
  • 0

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

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

  • 2

    我建议总是使用boost lexical_cast<> 代替 atoiatof 等垃圾 .

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

    除此之外你的代码还可以用于简单的东西 .

  • 3

    我在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;
    ...
    
  • 0

    它有点太大而无法包含在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 -style参数向量的输入 . 解析器处理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行(不包括测试) . 实例有点臃肿,因为解析表是实例的一部分(而不是类) . 但是你通常每个程序只需要一个实例,这种纯粹声明性方法的便利性非常强大,只需通过解析新输入就可以重置实例 .

相关问题