如果程序被指定像这样运行,那么在c++中解析命令行参数的最佳方式是什么:

prog [-abc] [input [output]]

是否有某种方法可以在标准库中实现这一点,或者我需要自己编写代码?


相关:

在unicode c++应用程序中解析命令行参数


当前回答

我喜欢C的getopt(),但是我老了。: -)

其他回答

GNU顶。

一个使用GetOpt的简单示例:

// C/C++ Libraries:
#include <string>
#include <iostream>
#include <unistd.h>

// Namespaces:
using namespace std;

int main(int argc, char** argv) {
    int opt;
    bool flagA = false;
    bool flagB = false;

    // Shut GetOpt error messages down (return '?'): 
    opterr = 0;

    // Retrieve the options:
    while ( (opt = getopt(argc, argv, "ab")) != -1 ) {  // for each option...
        switch ( opt ) {
            case 'a':
                    flagA = true;
                break;
            case 'b':
                    flagB = true;
                break;
            case '?':  // unknown option...
                    cerr << "Unknown option: '" << char(optopt) << "'!" << endl;
                break;
        }
    }

    // Debug:
    cout << "flagA = " << flagA << endl;
    cout << "flagB = " << flagB << endl;

    return 0;
}

如果有接受参数的选项,也可以使用optarg。

一个简单的解决方案是将argv放入std::map中,以便查找:

map<string, string> argvToMap(int argc, char * argv[])
{
    map<string, string> args;

    for(int i=1; i<argc; i++) {
        if (argv[i][0] == '-') {
            const string key = argv[i];
            string value = "";
            if (i+1 < argc && argv[i+1][0] != '-') {
                value = string(argv[i+1]);
                i++;
            }

            args[key] = value;
        }
    }

    return args;
}

使用示例:

#include <map>
#include <string>
#include <iostream>

using namespace std;

map<string, string> argvToMap(int argc, char * argv[])
{
    map<string, string> args;

    for(int i=1; i<argc; i++) {
        if (argv[i][0] == '-') {
            const string key = argv[i];
            string value = "";
            if (i+1 < argc && argv[i+1][0] != '-') {
                value = string(argv[i+1]);
                i++;
            }

            args[key] = value;
        }
    }

    return args;
}

void printUsage()
{
    cout << "simple_args: A sample program for simple arg parsing\n"
            "\n"
            "Example usage:\n"
            "    ./simple_args --print-all --option 1 --flag 2\n";
}

int main(int argc, char * argv[])
{
    auto args = argvToMap(argc, argv);

    if (args.count("-h") || args.count("--help")) {
        printUsage();
    }
    else if (args.count("--print-all")) {
        for (auto const & pair: args)
            cout << "{" << pair.first << ": " << pair.second << "}\n";
    }

    return 0;
}

输出:

$ ./simple_args --print-all --option 1 --flag "hello world"
{--flag: hello world}
{--option: 1}
{--print-all: }

这种方法肯定有很大的局限性,但我发现它很好地平衡了简单性和实用性。

我在一些项目中使用过GetPot: http://getpot.sourceforge.net/

主要特点:所有东西都在一个头文件中,没有构建的麻烦。只需将它保存在你机器上的某个地方,并在你的文件中使用main()

最近没有更新,但它有很好的文档记录,工作得很好。

还有另一种选择是精益平均c++选项解析器:

http://optionparser.sourceforge.net

它是一个只包含头文件的库(实际上只有一个头文件),与所有其他建议不同 也是独立的,即它没有任何依赖关系。特别是,它不依赖于STL。它甚至不使用异常或任何其他需要库支持的东西。这意味着它可以与普通C语言或其他语言链接,而无需引入“外国”库。

像boost::program_options一样,它的API提供了方便的直接访问选项, 也就是说,你可以这样写代码

如果 (选项[帮助]) ... ;

and

int VERBOSE = options[VERBOSE].count();

然而,与boost::program_options不同的是,这只是使用一个带有(用户提供的)enum索引的数组。这提供了没有权重的关联容器的便利。

它有良好的文档记录,并具有公司友好的许可证(MIT)。

tlmc++ OP包含了一个很好的格式化程序,用于使用可以执行的消息 行换行和列对齐在本地化程序时非常有用,因为它可以确保即使在具有较长消息的语言中输出也会很好。它还省去了手动格式化80列的麻烦。

Argstream与boost非常相似。Program_option:它允许将变量绑定到选项等。但是,它不处理存储在配置文件中的选项。