Сохраняются ли значения optarg при последующих вызовах getopt? - PullRequest
0 голосов
/ 27 ноября 2018

Экспериментально представляется, что я могу захватить последовательные значения optarg при итерации int getopt(int argc, char * const argv[], const char *optstring) и ссылаться на них позже, как в следующем примере программы:

// main.c

#include <stdio.h>
#include <unistd.h>

int main( int argc, char* argv[] )
{
  int opt;
  char o;
  char* a = NULL;
  char* b = NULL;

  while ( -1 != ( opt = getopt( argc, argv, "abcd:e:" ) ) )
  {
    char o = opt & 0xFF;

    switch ( o )
    {
      case 'a':
      {
        printf( "%c (%p): [%s]\n", o, optarg, (NULL == optarg ? "" : optarg ) );
        break;
      }
      case 'b':
      {
        printf( "%c (%p): [%s]\n", o, optarg, (NULL == optarg ? "" : optarg ) );
        break;
      }
      case 'c':
      {
        printf( "%c (%p): [%s]\n", o, optarg, (NULL == optarg ? "" : optarg ) );
        break;
      }
      case 'd':
      {
        printf( "%c (%p): [%s]\n", o, optarg, (NULL == optarg ? "" : optarg ) );
        a = optarg;
        break;
      }
      case 'e':
      {
        printf( "%c (%p): [%s]\n", o, optarg, (NULL == optarg ? "" : optarg ) );
        b = optarg;
        break;
      }
    }
  }

  printf( "(%p): [%s]\n", a, (NULL == a ? "" : a ) );
  printf( "(%p): [%s]\n", b, (NULL == b ? "" : b ) );

  return 0;
}

Компиляция и выполнение примера:

> gcc -g main.c && ./a.out -dabc -e def -a
d (0x7fffe8d1d2b2): [abc]
e (0x7fffe8d1d2b9): [def]
a ((nil)): []
(0x7fffe8d1d2b2): [abc]
(0x7fffe8d1d2b9): [def]

Вопрос : Это действительно?Т.е. действительные значения, отличные от NULL optarg, действительны после последовательных итераций getopt() и / или его последней итерации (когда он возвращает -1)?Т.е. безопасно ли захватывать последовательные значения и ссылаться на них позже (т.е. без strdup их)?Я не хочу предполагать, что мой экспериментальный код в целом корректен.

Страница руководства заявляет, что существует extern char* optarg, но не указывает, может ли он повторно использоваться последовательными вызовамиgetopt().

(Поскольку аргументы getopt равны argc и argv, это означает, что для optarg установлено смещение argv, и в этом случае я считаю, что это безопасночтобы захватить его последовательные значения, но я хотел бы узнать, если это правильное предположение).

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Страница man для состояний getopt:

optstring - строка, содержащая допустимые символы опции.Если за таким символом следует двоеточие, параметр требует аргумента, поэтому getopt () помещает указатель на следующий текст в том же элементе argv или текст следующего элемента argv в optarg

А также:

По умолчанию getopt () переставляет содержимое argv во время сканирования, так что в конечном итоге все неопции заканчиваются.

Это означает, что он не выделяет никакой памяти и не сохраняет текст в статических буферах, а работает непосредственно с указанным массивом указателей argv и просто дает вам адрес внутри него.

Вы можете проверить это поведение в коде:

#include <stdio.h>
#include <unistd.h>

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

    int opt, cur;

    while (-1 != (opt = getopt(argc, argv, "a:b:c:"))) {
        cur = optind - 1;
        printf("current elemnt = %d argv[%d] = %p optarg = %p delta = %d\n",
            cur, cur, argv[cur], optarg, (int)(optarg - argv[cur]));
    }

    return 0;
}
0 голосов
/ 28 ноября 2018

В соответствии со спецификацией POSIX getopt:

Функция getopt () возвращает следующий символ опции (если он найден)) из argv , который соответствует символу в optstring , если есть такой, который соответствует.Если параметр принимает аргумент, getopt () должен установить переменную optarg , указывающую на параметр-аргумент следующим образом:

  1. Еслиопция была последним символом в строке, на которую указывает элемент argv , тогда optarg должен содержать следующий элемент argv и optind должен быть увеличен на 2. Если результирующее значение optind больше, чем argc , это указывает на отсутствующий аргумент-опцию, и getopt () возвращает сообщение об ошибке.

  2. В противном случае optarg указывает на строку, следующую за символом опции в этом элементе argv и optind должны быть увеличены на 1.

(выделение мин.)

Это говорит, что optarg всегда указывает на элемент argv.Он никогда не копирует.

Поскольку элементы argv действительны до тех пор, пока работает ваша программа, ваш код действителен (копирование не требуется).


NB.Страница POSIX также показывает пример параметров командной строки с аргументами , которые по существу эквивалентны вашей версии:

char *ifile;
...
while ((c = getopt(argc, argv, ":abf:o:")) != -1) {
    switch(c) {
    ...
    case 'f':
        ifile = optarg;
        break;
    ...
...