Можно ли использовать getopt_long для анализа массивов строк, аналогичных аргументам командной строки в C-программе?

Я знаю, что getopt должен использоваться для анализа аргументов командной строки, а не строк.

Тем не менее, меня смущает тот факт, что если я передам ему массив строк, который "похож на" переменную argv, getopt_long, похоже, будет работать, но только в первый раз, когда я его вызываю. Во второй и все последующие моменты, которые я называю, он игнорирует любые аргументы и возвращает значения по умолчанию.

Причина, по которой я это делаю, заключается в том, что я превращаю приложение, которое принимало аргументы командной строки, в "интерактивную" его версию, которая запрашивает у пользователя некоторые аргументы, затем выполняет некоторые действия на основе этих аргументов, а затем запрашивает дополнительные аргументы и так далее.

Следующий код является минимальным примером, который воспроизводит ошибку

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

struct input_parameters{
    char * d; // data set
};

int solver_help(int argc, char* const argv[], struct input_parameters * p)
{
  int c;

  p->d = "default name";

  while (1)
  {
      static struct option long_options[] =
      {
          {"data",  required_argument,     0, 'd'},
          {0, 0, 0, 0}
      };
      /* getopt_long stores the option index here. */
      int option_index = 0;

      c = getopt_long (argc, argv, "d:",
                       long_options, &option_index);

      /* Detect the end of the options. */
      if (c == -1)
        break;

      switch (c)
      {
          case 'd': p->d = optarg;
              break;
          default:
              printf("wrong option specification\n");
              exit(-1);
      }
  }

  return 0 ;


}    


int main () {

    int argc_first = 3;
    char * const argv_first[] = { "getopt_test", "--data", "first" };
    struct input_parameters first_input;
    solver_help(argc_first, argv_first, &first_input);

    printf("I think the data is: %s\n", first_input.d);

    int argc_second = 3;
    char * const argv_second[] = { "getopt_test","--data", "second" };
    struct input_parameters second_input;
    solver_help(argc_second, argv_second, &second_input);

    printf("I think the data is: %s\n", second_input.d);

    return 0;
}

Выход этого кода

I think the data is: first
I think the data is: default name

1 ответ

Решение

Со страницы руководства для getopt:

Для того, чтобы использовать getopt() для оценки нескольких наборов аргументов или для оценки одного набора аргументов несколько раз, переменная optreset должен быть установлен в 1 до второго и каждого дополнительного набора звонков getopt()и переменная optind должен быть повторно инициализирован.

Небольшое изменение вашего кода дает желаемые результаты:

#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>

struct input_parameters {
    char * d; // data set
};

int solver_help(int argc, char* const argv[], struct input_parameters * p)
{
    p->d = "default name";

    static struct option long_options[] =
    {
        {"data",  required_argument,     0, 'd'},
        {0, 0, 0, 0}
    };

    int option_index = 0;

    optreset = 1;     /*  ADD THIS  */
    optind = 1;       /*  ADD THIS  */

    int c = getopt_long(argc, argv, "d:",
                        long_options, &option_index);

    switch ( c )
    {
        case -1:
            break;

        case 'd':
            p->d = optarg;
            break;

        default:
            printf("in default case...\n");
            printf("wrong option specification\n");
            exit(EXIT_FAILURE);
    }

    return 0;
}    

int main(void) {

    int argc_first = 3;
    char * const argv_first[] = { "getopt_test", "--data", "first" };
    struct input_parameters first_input;
    solver_help(argc_first, argv_first, &first_input);

    printf("I think the data is: %s\n", first_input.d);

    int argc_second = 3;
    char * const argv_second[] = { "getopt_test","--data", "second" };
    struct input_parameters second_input;
    solver_help(argc_second, argv_second, &second_input);

    printf("I think the data is: %s\n", second_input.d);

    return 0;
}

с выходом:

paul@horus:~/src/sandbox$ ./go
I think the data is: first
I think the data is: second
paul@horus:~/src/sandbox$ 
Другие вопросы по тегам