библиотека обработки командной строки - getopt

Может ли кто-нибудь помочь мне с функцией getopt?

Когда я в основном делаю следующее:

char *argv1[] = {"testexec","-?"};
char *argv2[] = {"testexec","-m","arg1"};
int  cOption;
/* test for -? */

setvbuf(stdout,(char*)NULL,_IONBF,0);
printf("\n argv1 ");
while (( cOption = getopt (2, argv1, "m:t:n:fs?")) != -1) {
    switch(cOption){
        case 'm':
            printf("\n -m Arg : %s \n",optarg);
            break;
        case '?':
            printf("\n -? Arg ");
            break;
        case 'n':
            printf("\n -n Arg : %s \n",optarg);
            break;
    }
}

printf("\n argv2 ");

while (( cOption = getopt (3, argv2, "m:t:n:fs?")) != -1) {
    switch(cOption){
        case 'm':
            printf("\n -m Arg : %s \n",optarg);
            break;
        case '?':
            printf("\n -? Arg : %s \n",optarg);
            break;
        case 'n':
            printf("\n -n Arg : %s \n",optarg);
            break;
    }
}

Я запускаю этот код на rhel3, который использует старую версию libc. Я не знаю, какой именно.

Теперь проблема в том, что getopt не работает во второй раз с argv2. Но если я закомментирую первый вызов getopt с помощью argv1, он сработает.

Может кто-нибудь сказать мне, что я здесь делаю не так?


person Community    schedule 11.02.2009    source источник


Ответы (4)


argv1 и 2 должны заканчиваться на 0:

char* argv1[] = {"par1", "par2", 0};

Изменить: Хорошо, я прочитал справочную страницу getopt и нашел следующее:

Переменная optind - это индекс следующего элемента, который будет обрабатываться в argv. Система инициализирует это значение до 1. Вызывающий может сбросить его до 1, чтобы перезапустить сканирование того же argv или при сканировании нового вектора аргументов.

Таким образом, установка optind = 1 между двумя вызовами в getopt заставляет его работать должным образом.

person Diego Sevilla    schedule 11.02.2009
comment
Хороший ответ, но, хотя это, безусловно, правда, я попытался изменить его в примере кода, и это не устранило конкретную проблему, о которой спрашивали. - person David Z; 11.02.2009
comment
Дэвид, ты прав. Я просто заметил эту ошибку и забыл об остальном :) Я отредактировал ответ, так как заметил, что если вы обновите значение optind до 1, код будет работать должным образом. С Уважением - person Diego Sevilla; 11.02.2009
comment
Осторожно: стандарт POSIX не утверждает, что сброс optind на 1 приведет к сбросу getopt () в исходное состояние, особенно если вы не полностью проанализировали первые аргументы. Например, если первым аргументом является -xy и вы остановитесь после обработки x, нет гарантии, что сброс optind сработает. - person Jonathan Leffler; 13.02.2009

Функция getopt() использует некоторые глобальные переменные, такие как optind и optarg, для хранения информации о состоянии между вызовами. После завершения обработки одного набора параметров в этих переменных остаются данные, которые вызывают проблемы со следующим набором параметров. Вы можете попытаться сбросить состояние getopt между вызовами, очистив переменные, но я не уверен, что это сработает, поскольку функция может использовать другие переменные, которые не задокументированы, и вы никогда не узнаете, получили ли вы их все; кроме того, он был бы совершенно непереносимым (т.е. если реализация getopt() изменится, ваш код сломается). Дополнительные сведения см. На странице руководства. Лучше не использовать getopt() для более чем одного набора аргументов в данной программе, если вы можете ей помочь.

Я не уверен, существует ли реальная функция для сброса состояния getopt (или, возможно, реентерабельная версия функции, которая позволяет вам сохранять состояние в ваших собственных переменных) ... Кажется, я помню, как однажды видел что-то подобное, но Не могу найти сейчас, когда смотрю: - /

person David Z    schedule 11.02.2009

Как указано на странице руководства:

"Программа, которая сканирует несколько векторов аргументов или повторно сканирует один и тот же вектор более одного раза и хочет использовать расширения GNU, такие как '+' и '-' в начале optstring, или изменяет значение POSIXLY_CORRECT между сканированиями, должна повторно инициализировать getopt (), сбросив optind на 0, а не на традиционное значение 1. (Сброс на 0 приводит к вызову внутренней процедуры инициализации, которая повторно проверяет POSIXLY_CORRECT и проверяет наличие расширений GNU в optstring.) "

person user2834940    schedule 01.10.2013

Есть ли причина, по которой вы не используете вместо этого getopt_long ()? На большинстве платформ getopt () просто вызывает _getopt_long () с переключателем для отключения длинных аргументов. Так обстоит дело почти со всеми известными мне платформами (которые все еще используются), включая Linux, BSD и даже новые ОС, такие как HelenOS - я знаю, что это я перенес getopt на его libc :)

ЛЮБОМУ, использующему вашу программу, намного проще иметь длинные варианты, по крайней мере, до тех пор, пока они не привыкнут к ней.

getopt_long () позволит вам использовать два (или более) индекса опций, которые могут оставаться `` живыми '' после того, как они завершат обработку аргументов, только внутренний (глобальный, не реентерабельный) должен быть повторно установлен, что не является большим по рукам.

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

Посмотрите на getopt.h, вы поймете, о чем я.

person Tim Post♦    schedule 11.02.2009
comment
Определить большинство платформ? HP-UX, Solaris, AIX - getopt () не вызывает getopt_long (). Это 3 из 6 вариантов Unix (BSD, Linux, MacOS X - остальные, которые имеют значение). - person Jonathan Leffler; 13.02.2009