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

prog [-abc] [input [output]]

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


相关:

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


当前回答

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

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

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

其他回答

boost::program_options和GNU getopt的建议是很好的。

然而,对于简单的命令行选项,我倾向于使用std::find

例如,在-f命令行参数后读取文件名。您还可以检测是否传入了一个单字选项,例如-h,以寻求帮助。

#include <algorithm>

char* getCmdOption(char ** begin, char ** end, const std::string & option)
{
    char ** itr = std::find(begin, end, option);
    if (itr != end && ++itr != end)
    {
        return *itr;
    }
    return 0;
}

bool cmdOptionExists(char** begin, char** end, const std::string& option)
{
    return std::find(begin, end, option) != end;
}

int main(int argc, char * argv[])
{
    if(cmdOptionExists(argv, argv+argc, "-h"))
    {
        // Do stuff
    }

    char * filename = getCmdOption(argv, argv + argc, "-f");

    if (filename)
    {
        // Do interesting things
        // ...
    }

    return 0;
}

使用这种方法需要注意的一点是,必须使用std::strings作为std::find的值,否则将对指针值执行相等性检查。


我希望它是可以编辑这个回应,而不是添加一个新的,因为这是基于原始的答案。我稍微重写了函数,并将它们封装在一个类中,下面是代码。我认为这样使用也很实用:

class InputParser{
    public:
        InputParser (int &argc, char **argv){
            for (int i=1; i < argc; ++i)
                this->tokens.push_back(std::string(argv[i]));
        }
        /// @author iain
        const std::string& getCmdOption(const std::string &option) const{
            std::vector<std::string>::const_iterator itr;
            itr =  std::find(this->tokens.begin(), this->tokens.end(), option);
            if (itr != this->tokens.end() && ++itr != this->tokens.end()){
                return *itr;
            }
            static const std::string empty_string("");
            return empty_string;
        }
        /// @author iain
        bool cmdOptionExists(const std::string &option) const{
            return std::find(this->tokens.begin(), this->tokens.end(), option)
                   != this->tokens.end();
        }
    private:
        std::vector <std::string> tokens;
};

int main(int argc, char **argv){
    InputParser input(argc, argv);
    if(input.cmdOptionExists("-h")){
        // Do stuff
    }
    const std::string &filename = input.getCmdOption("-f");
    if (!filename.empty()){
        // Do interesting things ...
    }
    return 0;
}

GNU C库中有这些工具,其中包括GetOpt。

如果你正在使用Qt并且喜欢GetOpt接口,那么froglogic已经在这里发布了一个不错的接口。

如果你只想自己处理命令行选项,最简单的方法是:

vector<string> args(argv + 1, argv + argc);

在main()的顶部。这将把所有命令行参数复制到std::strings的向量中。然后,您可以使用==轻松地比较字符串,而不是无休止的strcmp()调用。例如:

int main(int argc, char **argv) {
    vector<string> args(argv + 1, argv + argc);
    string infname, outfname;

    // Loop over command-line args
    // (Actually I usually use an ordinary integer loop variable and compare
    // args[i] instead of *i -- don't tell anyone! ;)
    for (auto i = args.begin(); i != args.end(); ++i) {
        if (*i == "-h" || *i == "--help") {
            cout << "Syntax: foomatic -i <infile> -o <outfile>" << endl;
            return 0;
        } else if (*i == "-i") {
            infname = *++i;
        } else if (*i == "-o") {
            outfname = *++i;
        }
    }
}

[编辑:我意识到我正在复制argv[0],程序的名称,到args -已修复。]

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

有很多好的库可用。

Boost Program Options是一个相当重量级的解决方案,因为将它添加到项目中需要构建Boost,而且语法有点令人困惑(在我看来)。但是,它几乎可以做任何事情,包括让命令行选项覆盖配置文件中设置的选项。

SimpleOpt是一个相当全面但简单的命令行处理器。它是一个单一的文件,具有简单的结构,但只处理将命令行解析为选项,您必须进行所有的类型和范围检查。它适用于Windows和Unix,并且还附带了一个适用于Windows的glob版本。

getopt在Windows上可用。它与Unix机器上的相同,但它通常是一个GPL库。