Как в С++ использовать только длинные параметры с обязательным аргументом?

В программе на С++ я хотел бы иметь опцию «только для длинных» с обязательным аргументом. Ниже приведен мой минимальный пример с использованием getopt_long(), но это не работает:

#include <getopt.h>
#include <cstdlib>
#include <iostream>
using namespace std;

void help (char ** argv)
{
  cout << "`" << argv[0] << "` experiments with long options." << endl;
}

void parse_args (int argc, char ** argv, int & verbose, int & param)
{
  int c = 0;
  while (1)
  {
    static struct option long_options[] =
      {
        {"help", no_argument, 0, 'h'},
        {"verbose", required_argument, 0, 'v'},
        {"param", required_argument, 0, 0}
      };
    int option_index = 0;
    c = getopt_long (argc, argv, "hv:",
                     long_options, &option_index);
    cout << "c=" << c << endl;
    if (c == -1)
      break;
    switch (c)
    {
    case 0:
      if (long_options[option_index].flag != 0)
        break;
      printf ("option %s", long_options[option_index].name);
      if (optarg)
        printf (" with arg %s", optarg);
      printf ("\n");
      break;
    case 'h':
      help (argv);
      exit (0);
    case 'v':
      verbose = atoi(optarg);
      break;
    case 'param':
      param = atoi(optarg);
      break;
    case '?':
      abort ();
    default:
      abort ();
    }
  }
}

int main (int argc, char ** argv)
{
  int verbose = 0;
  int param = 0;
  parse_args (argc, argv, verbose, param);
  cout << "verbose=" << verbose << " param=" << param << endl;
  return EXIT_SUCCESS;
}

Я компилирую его с помощью этой команды (версия gcc 4.1.2 20080704 Red Hat 4.1.2-46):

g++ -Wall test.cpp

Это говорит мне следующее:

test.cpp:44:10: warning: character constant too long for its type

И вот результат:

$ ./a.out -v 2 --param 3
c=118
c=0
option param with arg 3
c=-1
verbose=2 param=0

Я пытался заставить его работать на ideone, но он даже не распознает опцию -v.

Как указано trojanfoe в его комментариях к другому вопросу, должна быть возможность использовать параметры "только для длинных", поскольку GNU tar Имеет ли это. Однако GNU tar использует argp, и у меня возникают трудности понимание его исходного кода.

Может ли кто-нибудь дать мне минимальный пример, который работает с GNU getopt_long() или argp()?


person tflutre    schedule 18.04.2012    source источник
comment
Вместо этого вы можете рассмотреть возможность использования Boost.Program_options. .   -  person Jerry Coffin    schedule 18.04.2012
comment
@JerryCoffin спасибо за совет, я бы предпочел использовать argp, тем более что с его помощью можно решить мою проблему (см. Пример GNU tar)   -  person tflutre    schedule 18.04.2012
comment
Несомненно, можно заставить argp выполнить эту работу. Boost просто делает это намного лучше и чище.   -  person Jerry Coffin    schedule 18.04.2012


Ответы (4)


Есть две проблемы:

  1. Согласно коду примера (ваша ссылка), последний параметр, определенный в структуре, должен быть {0,0,0,0}. Я рекомендую изменить определение на

    static struct option long_options[] =
      {
        {"help", no_argument, 0, 'h'},
        {"verbose", required_argument, 0, 'v'},
        {"param", required_argument, 0, 0},
        {0,0,0,0}
      };
    
  2. (И что еще более важно) вы должны включить код, который фактически обрабатывает опцию «param». Вы делаете это в случае '0':

    case 0:
      if (long_options[option_index].flag != 0)
        break;
      if (strcmp(long_options[option_index].name,"param") == 0)
        param = atoi(optarg);
      break;
    

Как видите, я использую функцию strcmp для сравнения строк; для этого вам нужно #include <cstring>. Кстати, вам также понадобится #include <cstdio> для использования printf.

С этими изменениями программа у меня работала корректно (проверено на GCC 4.5.1).

person jogojapan    schedule 18.04.2012
comment
спасибо, я также нашел примерно такое же решение (см. ниже), но ваше решение чище - person tflutre; 18.04.2012

В вашем случае вы используете:

case 'param':

что дает вам предупреждение, потому что компилятор ожидает один символ в этом месте.

person P.P    schedule 18.04.2012
comment
Вы можете, но интерпретация зависит от компилятора. Вы правы в том, что это источник предупреждения компилятора. - person Jonathan Leffler; 18.04.2012
comment
@Thiruvalluvar спасибо, но меня не очень беспокоит предупреждение, так как оно исчезнет, ​​как только кто-то найдет решение моей проблемы, а именно, как использовать опцию только для длинных слов. - person tflutre; 18.04.2012
comment
Если вы хотите использовать строку в качестве параметра, вы можете использовать str1.compare(str2) и передать возвращаемое значение в swtich-case. @JonathanLeffler отредактировал это сейчас. - person P.P; 18.04.2012
comment
@Thiruvalluvar Я не знал, что это возможно, как бы вы это сделали конкретно? (извините, но я не профессиональный программист на С++...) - person tflutre; 18.04.2012
comment
getopt_long возвращает int, и вы используете его значение в случае переключения. Но ваши операторы case проверяют наличие символов. Это то, что вы собираетесь делать? - person P.P; 18.04.2012
comment
@Thiruvalluvar getopt_long возвращает int, но соответствует char (см. таблицу ASCII). Например, когда c=118, короткий вариант — v. Как бы то ни было, я нашел решение своей проблемы, см. мой ответ ниже. - person tflutre; 18.04.2012

На самом деле я понял, что должен проверять значение option_index, когда c имеет значение 0, вот так. Такого случая нет в примерах GNU libc, так что вот он:

switch (c)
{
case 0:
  if (long_options[option_index].flag != 0)
    break;
  if (option_index == 2)
  {
    param = atoi(optarg);
    break;
  }
case 'h':
  help (argv);
  exit (0);
case 'v':
  verbose = atoi(optarg);
  break;
case '?':
  abort ();
default:
  abort ();
}
person tflutre    schedule 18.04.2012

Другим решением является использование значения члена «флаг», определенного в параметре структуры.

Настройте параметры, как показано ниже:

int param_flag = 0;

{"param", required_argument, &param_flag, 1}

Затем;

case 0:
    if (param_flag == 1) {
        do_something;
    }

Подробнее об опции структуры см. в man getopt_long.

person Hiroshi Araki    schedule 26.10.2016