Usando getopt vs Boost em C ++ para lidar com argumentos

Ei pessoal, este é o meu pequeno tutorial, em vez da experiência minha ao decidir qual manipulador de argumento usar. Normalmente em C ++ torna-se complicado usar a versão básica de arg counts e argv. Portanto, prefiro usar bibliotecas padrão para o mesmo. Torna a sua vida um pouco mais fácil.

Vamos começar com o impulso. Sempre que vejo uma biblioteca boost, fico muito tentado a usá-la, já que muitos dos meus programas a usam, especialmente os assíncronos. Mas, para algo tão razoavelmente simples e sucinto como o analisador de opções, preciso de impulso? Dando uma olhada em suas bibliotecas, é isso que está incluído.

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/positional_options.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/errors.hpp>
#include <boost/program_options/option.hpp>
#include <boost/program_options/value_semantic.hpp>
#include <boost/program_options/version.hpp>

Essas são muitas bibliotecas que me fazem pensar: eu realmente preciso delas?

A seguir está a aparência do programa de aumento real

#include<iostream>
#include<boost/program_options.hpp>

using namespace std;

int main(int argc, char **argv)
{

namespace po = boost::program_options;
po
::options_description desc("Allowed options");
desc
.add_options()
("help", "describe arguments")
("flag", po::value<int>(), "flag");

po
::variables_map vm;
po
::store(po::parse_command_line(argc, argv, desc), vm);
po
::notify(vm);

if (vm.count("help")) {
cout
<< desc << "n";
return 1;
}

if (vm.count("flag")) {
cout
<< "flag is set to "
<< vm["flag"].as<int>() << ".n";
} else {
cout
<< "flag not set.n";
}
}

O programa acima é uma cópia do exemplo mencionado no site boost. O tipo de dependências e bibliotecas envolvidas me faz sentir um inferno. Não, ofensa para aumentar os fãs. Boost realmente é uma ótima biblioteca, mas comum, precisamos de tantos arquivos de cabeçalho e namespaces apenas para um analisador de opções? Acho que não!

Agora é aqui que getopt confere sua simplicidade.

#include<iostream>
#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>


using namespace std;
int main(int argc, char **argv)
{
int opt,a,b,c;
while ((opt = getopt(argc,argv,"abc:d")) != EOF)
switch(opt)
{
case 'a': a = 1; cout <<" a is enabled"<<a <<endl; break;
case 'b': b = 1; cout <<" b is enabled"<<b <<endl; break;
case 'c': c = 1; cout << "value of c is"<< optarg <<endl ; break;
case '?': fprintf(stderr, "usuage is n -a : for enabling a n -b : for enabling b n -c: <value> ");
default: cout<<endl; abort();
}

return 0;
}

Definitivamente, isso parece muito mais simples. Mas getopt tem seu próprio conjunto de ressalvas. Em primeiro lugar, quando você chama getopt, as seguintes variáveis ​​são definidas.

  1. A variável característicag destina-se aos argumentos que possuem alguns parâmetros a serem passados. Como a opção c no programa acima. um pode facilmente bagunçar, se acontecer de você usar isso em seu programa. (sim, existem maneiras de evitá-lo)
  2. As opções passadas para a função getopt não parecem muito boas. abc: d informa que c é uma opção em que algum parâmetro é esperado.
  3. Você precisa ter sua própria lógica para multiplexar vários argumentos. Por exemplo, se eu quiser que o usuário não tenha -c 5 -f 6 para serem passados ​​juntos ou não tenha as opções -a -b definidas ao mesmo tempo. Ele precisa ser tratado pelo meu código e não pelo analisador de opções. Muitos de vocês podem estar discutindo que o analisador de opções não foi feito para fazer isso, mas seria bom ter isso como um recurso.

Por último, ambos os métodos de análise de argumentos têm seus prós e contras. Mas não existe uma solução que implique o melhor de ambos. É hora de começar a programar minha própria biblioteca 🙂