Парсинг дополнительных аргументов командной строки в C

у меня есть программа, которая принимает необязательные аргументы. Необходимыми аргументами являются файл и целые числа (1 или более). Необязательные аргументы представляют собой сочетание строк и целых чисел.

поэтому правильный ввод в командной строке может быть:

./main trace_file 8 12 # (only necessary arguments)

./main –n 3000000 –p page.txt trace_file 8 7 4 # (with optional arguments)

мне нужно получить целые числа после trace_file в массив. Мне трудно понять, как это сделать, когда включены необязательные аргументы, потому что в командной строке находится другое целое число. Толчок в правильном направлении был бы очень признателен, потому что я не могу понять, как это сделать.

изменить: до сих пор все у меня есть для разбора аргументов это:

for(j=2, k=0; j<argc; j++, k++) {
    shift += atoi(argv[j]);
    shiftArr[k] = 32 - shift;
    bitMaskArr[k] = (int)(pow(2, atoi(argv[j])) - 1) << (shiftArr[k]);
    entryCnt[k] = (int)pow(2, atoi(argv[j]));
}

но это будет работать только тогда, когда необязательные аргументы не вводятся.

4 ответов


Я не вижу никаких серьезных проблем, если вы используете разумно совместимую с POSIX версию getopt().

исходный код (goo.c)

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

/*
   ./main trace_file 8 12 # (only necessary arguments)

   ./main –n 3000000 –p page.txt trace_file 8 7 4 # (with optional arguments)
 */

static void usage(const char *argv0)
{
    fprintf(stderr, "Usage: %s [-n number][-p pagefile] trace n1 n2 ...\n", argv0);
    exit(EXIT_FAILURE);
}

int main(int argc, char **argv)
{
    int number = 0;
    char *pagefile = "default.txt";
    char *tracefile;
    int opt;

    while ((opt = getopt(argc, argv, "n:p:")) != -1)
    {
        switch (opt)
        {
        case 'p':
            pagefile = optarg;
            break;
        case 'n':
            number = atoi(optarg);
            break;
        default:
            usage(argv[0]);
        }
    }

    if (argc - optind < 3)
    {
        fprintf(stderr, "%s: too few arguments\n", argv[0]);
        usage(argv[0]);
    }

    tracefile = argv[optind++];
    printf("Trace file: %s\n", tracefile);
    printf("Page file:  %s\n", pagefile);
    printf("Multiplier: %d\n", number);
    for (int i = optind; i < argc; i++)
        printf("Processing number: %d (%s)\n", atoi(argv[i]), argv[i]);
    return 0;
}

сборник

$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>      -Wold-style-definition -Werror goo.c -o goo

пример работает

$ ./goo trace_file 8 12
Trace file: trace_file
Page file:  default.txt
Multiplier: 0
Processing number: 8 (8)
Processing number: 12 (12)
$ ./goo -n 3000000 -p page.txt trace_file 8 7 4
Trace file: trace_file
Page file:  page.txt
Multiplier: 3000000
Processing number: 8 (8)
Processing number: 7 (7)
Processing number: 4 (4)
$

Я немного подумал об этом, и для getopt нет простого способа вернуть несколько аргументов. Я задался вопросом об определении " y::", но отклонил это. Варианты

1) имеют 2 варианта y и Y используют по одному для каждого int и логический флаг, чтобы поймать исключение, где Y определен, но Y нет.

2) оставьте сложные параметры, такие как y, из цикла getopt. После того, как getopt обработал параметры и перетасованные аргументы. Предварительно обработайте эти аргументы, чтобы захватить - y операнды и код в аргументах процесса, чтобы пропустить-y, и это операнды

3) более обычным для команд *nix является предоставление нескольких значений в качестве одного аргумента, который сам является списком значений, разделенным запятыми. Вы достигаете этого, добавляя "y:" к вашей обработке getopt. Строка, на которую он указывает, также должна быть проанализирована на 2 токена A и B из строки A,B


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

  • создайте новые переменные myargc, myargv и скопируйте в них argc и argv.

  • функции записи, которые имеют дело с парными аргументами (например, "- N 300000" или "-P страница.формат txt." Передайте myargc и myargv в эти функции по ссылке. Каждая такая функция возвращает значение, связанное с параметром (напр., 300000 или страницы.txt), если он был найден, или недопустимое значение (например, -1 или""), если оно не было. И в любом случае, функция выводит оба элемента из myargv и уменьшает myargc на 2.

  • Если у вас также есть аргументы, которые являются только отдельными флагами, напишите функции для тех, которые возвращают логическое значение, указывающее, найден ли флаг, удалите флаг из myargv и уменьшите myargc на 1. (Вы можете иметь дело с trace_file таким образом, даже если это необязательно. Я предполагаю, что trace_file-это просто флаг, а не связанный с 8, который следует за ним.)

  • сначала вызовите функции для каждого из ваших необязательных аргументов. То, что осталось в myargc и myargv после того, как вы их вызвали, должно быть только вашими необходимыми аргументами, и вы можете обрабатывать их, как обычно.


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

создайте новые переменные myargc, myargv и скопируйте в них argc и argv.

функции записи, которые имеют дело с парными аргументами (например, "- N 300000" или "-P страница.формат txt." Передайте myargc и myargv в эти функции по ссылке. Каждая такая функция возвращает значение, связанное с аргументом (например, 300000 или page.txt), если он был найден или недействителен значение (например, -1 или ""), если это не так. И в любом случае функция удаляет оба элемента из myargv и уменьшает myargc на 2.

Если у вас также есть аргументы, которые являются только отдельными флагами, напишите функции для тех, которые возвращают логическое значение, указывающее, найден ли флаг, удалите флаг из myargv и уменьшите myargc на 1. (Вы можете иметь дело с trace_file таким образом, даже если это необязательно. Я предполагаю, что trace_file-это просто флаг, а не связанный с 8, который следует он.)

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