Как выбрать один из вариантов?

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

enum mode{
    read,
    write
};
enum mode mode;

int opt;
while((opt = getopt("rw")) != -1){
    switch(opt){
        case 'w':
            mode = write;
            break;
        case 'r':
            mode = read;
            break;
        default:
            fprintf(stderr, "Usage: %s [-r-w]\n", argv[0]");
            exit(1);
    }
}

Проблема в том, как это работает, теперь можно пройти оба -r а также -w вариант, который не имеет смысла. Я хочу, чтобы был выбран только один из двух режимов.

Что такое "идиоматический" способ сделать это?

3 ответа

Как выбрать один из вариантов?
Я хочу, чтобы пользователь выбрал ровно один режим.

Создайте вспомогательную функцию, которая допускает один и только один допустимый режим.

enum mode get_mode(void) {
  int opt = getopt("rw");
  if (opt != -1 && getopt("rw") == -1) {
    switch(opt){
      case 'w': return write;
      case 'r': return read;
    }
  }
  fprintf(stderr, "Usage: %s [-r-w]\n", argv[0]");
  exit(1);
}

Если бы это был я, я бы использовал что-то вроде этого:

enum mode { DEFAULT, READ, WRITE };
enum mode mode = DEFAULT;

int opt;
while ((opt = getopt("rw")) != -1)
{
    switch (opt)
    {
    case 'w':
        if (mode == READ)
            err_exit("cannot use mutually exclusive options -r and -w");
        mode = WRITE;
        break;
    case 'r':
        if (mode == WRITE)
            err_exit("cannot use mutually exclusive options -r and -w");
        mode = READ;
        break;
    default:
        fprintf(stderr, "Usage: %s [-r|-w]\n", argv[0]);
        exit(1);
    }
}

if (mode == DEFAULT)
    mode = READ;    // Or write, whichever is your default

Обратите внимание, что это позволяет избежать использования неинициализированной переменной mode,

Я предполагаю подходящую функцию err_exit() который сообщает об ошибке и выходит. Моя реализация также имеет err_usage() который будет использоваться err_usage("[-r|-w]"); (и использует вызов функции, err_setarg0(argv[0]), чтобы записать название программы). Вы можете найти мои реализации в моем хранилище SOQ (вопросы о переполнении стека) на GitHub в виде файлов stderr.c а также stderr.h в подкаталоге src / libsoq.

Я также избегаю использовать такие имена, как read а также write поскольку они также используются для функций и поэтому скрыты константами перечисления в нижнем регистре (они находятся в пространстве имен обычного идентификатора, так же, как функции и переменные). На самом деле, я бы, вероятно, использовал такой префикс, как OPT_ (следовательно, OPT_DEFAULT, OPT_READ, OPT_WRITE) чтобы избежать коллизий с другими возможными использованиями имен.

Это настолько субъективно, это не очень хороший вопрос, но вот некоторые мысли:

(1) Один из подходов - иметь только один вариант. Поведение по умолчанию читается, если указана опция -w, то режим записывается.

(2) Некоторые Unix-программы решают проблему, говоря "Последний аргумент выигрывает"

(3) Еще один подход заключается в использовании отдельных переменных и обнаружении условия, что оба флага были установлены.

Я видел все три подхода. Возможно, есть и другие идеи.

Другие вопросы по тегам