Парсинг дополнительных аргументов командной строки в 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, который следует он.)
сначала вызовите функции для каждого из ваших необязательных аргументов.