библиотека обработки командной строки - getopt - PullRequest
5 голосов
/ 11 февраля 2009

Может кто-нибудь помочь мне с функцией 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, он сработает.

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

Ответы [ 4 ]

12 голосов
/ 11 февраля 2009

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

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

Редактировать : ОК, я прочитал справочную страницу getopt и нашел:

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

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

4 голосов
/ 11 февраля 2009

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

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

2 голосов
/ 01 октября 2013

Как указано в справочной странице:

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

1 голос
/ 11 февраля 2009

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

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

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

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

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

...