如何将命令行参数与c++中的选项一起传递给函数

How shall command line arguments be passed to a function along with options in c++?

本文关键字:一起 选项 函数 命令行 参数 c++      更新时间:2023-10-16

我必须通过使用命令行参数(argv,argc)在c++中的函数内部传递系统配置的详细信息。函数如下所示:

  function(char * array[]){
    windows_details = array[1];
    graphic_card = array[2];
    ram_detail = array[3];
    procesor_detail = array[4];
  }
 int main(int argc, char *argv[]){
   char *array[] = { argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]};
   function(array);
 }

因此,当我执行如下程序exe时,我得到了正确的输出:

 sample.exe windows_32bit nividia 5Gb i7processor

但我担心的是,每次值都必须按照特定的顺序排列,即用户必须注意"windows_details"将是第一个命令行参数,然后是"graphic_card",就像ram_details和processor_details一样,所以这个解决方案是不可靠的,即如果值序列互换,结果将不正确。我希望解决方案与序列无关,无论是序列,在正确的位置替换的值,以及作为值传递给选项的命令行参数。例如:

sample.exe --configuration i7_processor 5GB windows_32bit nividia or
sample.exe --configuration 5GB i7_processor nividia windows_32bit or
sample.exe --configuration nividia windows_32bit 5GB i7_processor
.
.

所以,和上面一样,有一个选项"--configuration",然后是任何序列中的细节。我尝试添加选项部分如下,但不起作用:

int main(int argc, char *argv[]){
   char *array[] = { argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]};
   std::string arg = *(reinterpret_cast<std::string*>(&array));
   if (arg == "--configuration"){
    function(array);
    }
    else {
    std::cout << "Usage " << argv[0] << "t--configtt Specify the configuration of target" << std::endl;
    return 1;
    }
   return 0;       
 }

所以,请帮我解决我的问题。我该怎么做才能让它在增加选项的同时变得更健壮?

您应该使用getoptBoost.ProgramOptions*(reinterpret_cast<std::string*>(&array))很傻,不会做你认为它会做的事。

关于如何使用两者,有很多教程。以下是getopt手册中的一个示例和Boost.ProgramOptions文档的链接

一个简单的BPO示例如下:

    po::options_description desc("Allowed options");
    desc.add_options()
        ("help", "produce help message")
        ("arch", po::value< string >(),
              "Windows version")
        ("card", po::value< string >(),
              "Graphics card")
        ("ram", po::value< string >(),
              "Amount of RAM")
        ("cpu", po::value< string >(),
              "Type of processor")
    ;
    po::variables_map vm;
    po::store(po::command_line_parser(ac, av).
              options(desc).run(), vm);
    po::notify(vm);
    if (vm.count("help")) {
        cout << "Usage: options_description [options]n";
        cout << desc;
        return 0;
    }

如果你愿意,你可以包括对位置选项的支持,但我不完全清楚你打算如何在没有显式开关的情况下区分各种选项。

Boost.Program_options应该是实现这一目标的最佳选择,但是,如果您不想要boost,并且可以更改函数调用以接受映射,则可以使用非常容易维护和可读的代码,如下所示:


void function( std::unordered_map<std::string, std::string>& arrayMap )
{
    windows_details = arrayMap ["--configuration"];
    graphic_card =    arrayMap ["--graphic_card"];
    ram_detail =      arrayMap ["--ram_detail"];
    procesor_detail = arrayMap ["--procesor_detail"];
}

使用std::find 提取参数的函数

char* extractOption(char** startItr, char** endItr, 
                     const std::string& searchParam)
{
    char ** itr = std::find(startItr, endItr, searchParam);
    if (itr != endItr && ++itr != endItr)
    {
        return *itr;
    }
    return 0;
}

然后你可以使用提取函数来填充地图,如下所示,(仅限伪代码):

int main(int argc, char * argv[])
{
    std::unordered_map<std::string, std::string> optionMap;
    std::string options[] = { "--configuration", 
                              "--processor_details" , 
                              "--graphic_card" };
    for(const auto& opts: options)
    {
       char * value= extractOption(argv, argv + argc, opts );
       if (value)
       {
           optionMap[opts] = value ;
       }
       else
       {
           std::cout << "Not found : " << opts << 'n';
       }
     }
    function( optionMap ) ;
    return 0;
}

See Here

另一种没有第三方库的简单方法是using specific flags作为(-p,-s,-c…),与参数描述或角色相对应。

然后,在您的代码中,您将得到如下内容:

if (i + 1 != argc) // Check that we haven't finished parsing already
    if (argv[i] == "-f") {
        // We know the next argument *should* be the filename:
        myFile = argv[i + 1];
    } else if (argv[i] == "-p") {
        myPath = argv[i + 1];
    } else if (argv[i] == "-o") {
        myOutPath = argv[i + 1];
    } else {
        std::cout << "Not enough or invalid arguments, please try again.n";
        Sleep(2000);
                 /*
                  *  Sleep for 2 seconds to allow user (if any) to read above statement. 
                  *  The issue with this is that if we're a backend program to a GUI as mentioned above; 
                  *  that program would also sleep for 2 seconds. Most programs don't
                  *  have this - the console will keep the text there until it scrolls off the page or whatever, so you may aswell leave it out.
                  ***/
        exit(0);
    }
如果您想用一种简单的方式让程序看起来"智能",就会想到

regex。

这里有一个简单的开始,你可以根据自己的意愿添加更多选项和错误检查。

#include <iostream>
#include <regex>
#include <string>
#include <vector>
#include <algorithm>
#include <cstring>
/*
 sample.exe --configuration i7_processor 5GB windows_32bit nividia
 sample.exe --configuration 5GB i7_processor nividia windows_32bit
 sample.exe --configuration nividia windows_32bit 5GB i7_processor
 */
template<class Iter>
std::pair<Iter, Iter> find_config(Iter first, Iter last)
{
    auto begin = std::find(first, last, std::string("--configuration"));
    if (begin == last)
    {
        return { last, last };
    }
    begin = std::next(begin);
    auto end = std::find_if(begin, last, [](auto& opt) {
        return opt.substr(0, 2) == "--";
    });
    return { begin, end };
}
struct configuration
{
    std::string processor = "not set";
    unsigned long long memory = 0;
    std::string os = "not set";
    std::string graphics = "not set";
};
std::ostream& operator<<(std::ostream& os, const configuration& conf)
{
    os <<   "processor = " << conf.processor;
    os << "nmemory    = " << conf.memory;
    os << "nos        = " << conf.os;
    os << "ngraphics  = " << conf.graphics;
    return os;
}
const std::regex re_processor("(.*)_processor", std::regex::icase);
const std::regex re_memory("(\d+)(mb|gb)", std::regex::icase);
template<class Iter>
auto parse_config(Iter first, Iter last) -> configuration
{
    configuration result;
    for ( ; first != last ; ++first)
    {
        auto& option = *first;
        std::smatch match;
        if (std::regex_match(option, match, re_processor))
        {
            result.processor = match[1].str();
            continue;
        }
        if (std::regex_match(option, match, re_memory))
        {
            unsigned long long num = std::stoi(match[1].str());
            auto mult = match[2].str();
            std::transform(mult.begin(), mult.end(), 
                           mult.begin(), 
                           [](auto& c) { return std::toupper(c); });
            if (mult == "GB") {
                num *= 1024 * 1024 * 1024;
            }
            else {
                num *= 1024 * 1024;
            }
            result.memory = num;
            continue;
        }
    }
    return result;
}
int main(int argc, const char* const * argv)
{
    std::vector<std::string> args(argv, argv + argc);
    const auto& progname = &args[0];
    auto config_range = find_config(std::next(std::begin(args)), std::end(args));
    auto configuration = parse_config(config_range.first, config_range.second);
    std::cout << configuration << std::endl;
}

示例运行:

$ sample --configuration i7_processor 5GB windows_32bit nividia
processor = i7
memory    = 5368709120
os        = not set
graphics  = not set
$