在 C 中解析可选的命令行参数
Parsing optional command line arguments in 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]));
}
但这只有在没有输入可选参数时才有效。
我已经考虑了一下,getopt 没有简单的方法 return 多个参数。我确实对定义 "y::" 感到疑惑,但已经忽略了这一点。选项是
1) 有 2 个选项 y 和 Y 为每个 int 使用一个选项,并使用一个布尔标志来捕获定义了 y 而 Y 未定义的异常。
2) 将像 y 这样的复杂选项排除在 getopt 循环之外。一旦 getopt 处理了选项并打乱了参数。预处理这些参数以捕获过程参数中的 -y 操作数和代码以跳过 -y 及其操作数
3) 在 *nix 命令中更常见的是将多个值作为单个参数提供,该参数本身是一个逗号分隔的值列表。您可以通过将 "y:" 添加到您的 getopt 处理来实现这一点。它指向的字符串也需要从字符串 A,B
解析为 2 个标记 A 和 B
如果您使用 getopt()
的合理 POSIX 兼容版本,我没有发现任何重大问题。
源代码(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() 或其他一些为您完成繁重工作的函数,那么可能的策略是:
创建新变量myargc、myargv,并将argc和argv复制到其中。
编写处理成对参数的函数(如“-n 300000”或“-p page.txt”)。将 myargc 和 myargv 传递给这些函数通过引用. 每个这样的函数 returns 与参数关联的值(例如,300000 或 page.txt)如果找到,或者无效值(例如 -1 或“”)如果事实并非如此。在任何一种情况下,函数 都会从 myargv 中删除 两项,并将 myargc 减 2。
如果您还有一些只是单独标志的参数,请为那些 return 布尔值的函数编写指示是否找到标志的函数,从 myargv 中删除标志,并将 myargc 减 1 .(你可以这样处理 trace_file,即使它不是可选的。我假设 trace_file 只是一个标志,与它后面的 8 无关。 )
首先为每个可选参数调用函数。 myargc 和 myargv 调用完后剩下的东西应该只是你需要的参数,你可以像往常一样处理它们。
如果您不能使用 getopt() 或其他一些为您完成繁重工作的函数,那么可能的策略是:
创建新变量 myargc、myargv,并将 argc 和 argv 复制到其中。
编写处理成对参数的函数(如“-n 300000”或“-p page.txt”)。通过引用将 myargc 和 myargv 传递给这些函数。每个这样的函数 returns与参数关联的值(例如 300000 或 page.txt)如果找到,或者无效值(例如 -1 或“”)如果没有找到。在任何一种情况下,该函数都会删除这两个项目来自 myargv 并将 myargc 减 2.
如果您也有只是单独标志的参数,请为那些 return 布尔值的参数编写函数,指示是否找到标志,从 myargv 中删除标志,并将 myargc 减 1。(您可以处理用 trace_file 这样,即使它不是可选的。我假设 trace_file 只是一个标志,与它后面的 8 无关。)
首先为每个可选参数调用函数。
我有一个接受可选参数的程序。必要的参数是一个文件和整数(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]));
}
但这只有在没有输入可选参数时才有效。
我已经考虑了一下,getopt 没有简单的方法 return 多个参数。我确实对定义 "y::" 感到疑惑,但已经忽略了这一点。选项是
1) 有 2 个选项 y 和 Y 为每个 int 使用一个选项,并使用一个布尔标志来捕获定义了 y 而 Y 未定义的异常。
2) 将像 y 这样的复杂选项排除在 getopt 循环之外。一旦 getopt 处理了选项并打乱了参数。预处理这些参数以捕获过程参数中的 -y 操作数和代码以跳过 -y 及其操作数
3) 在 *nix 命令中更常见的是将多个值作为单个参数提供,该参数本身是一个逗号分隔的值列表。您可以通过将 "y:" 添加到您的 getopt 处理来实现这一点。它指向的字符串也需要从字符串 A,B
解析为 2 个标记 A 和 B如果您使用 getopt()
的合理 POSIX 兼容版本,我没有发现任何重大问题。
源代码(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() 或其他一些为您完成繁重工作的函数,那么可能的策略是:
创建新变量myargc、myargv,并将argc和argv复制到其中。
编写处理成对参数的函数(如“-n 300000”或“-p page.txt”)。将 myargc 和 myargv 传递给这些函数通过引用. 每个这样的函数 returns 与参数关联的值(例如,300000 或 page.txt)如果找到,或者无效值(例如 -1 或“”)如果事实并非如此。在任何一种情况下,函数 都会从 myargv 中删除 两项,并将 myargc 减 2。
如果您还有一些只是单独标志的参数,请为那些 return 布尔值的函数编写指示是否找到标志的函数,从 myargv 中删除标志,并将 myargc 减 1 .(你可以这样处理 trace_file,即使它不是可选的。我假设 trace_file 只是一个标志,与它后面的 8 无关。 )
首先为每个可选参数调用函数。 myargc 和 myargv 调用完后剩下的东西应该只是你需要的参数,你可以像往常一样处理它们。
如果您不能使用 getopt() 或其他一些为您完成繁重工作的函数,那么可能的策略是:
创建新变量 myargc、myargv,并将 argc 和 argv 复制到其中。
编写处理成对参数的函数(如“-n 300000”或“-p page.txt”)。通过引用将 myargc 和 myargv 传递给这些函数。每个这样的函数 returns与参数关联的值(例如 300000 或 page.txt)如果找到,或者无效值(例如 -1 或“”)如果没有找到。在任何一种情况下,该函数都会删除这两个项目来自 myargv 并将 myargc 减 2.
如果您也有只是单独标志的参数,请为那些 return 布尔值的参数编写函数,指示是否找到标志,从 myargv 中删除标志,并将 myargc 减 1。(您可以处理用 trace_file 这样,即使它不是可选的。我假设 trace_file 只是一个标志,与它后面的 8 无关。)
首先为每个可选参数调用函数。