在C语言中解析可选的命令行参数

7
我是一名辅助翻译,以下是您需要翻译的内容:

我有一个程序,可以输入可选参数。必需的参数是文件和整数(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]));
}

但是只有在没有输入可选参数时,才能起作用。

这是一篇比较长的帖子。这个程序是为了学校的一个作业,我们在模拟地址分页。所以,我要问的问题实际上只是我程序中的一个“简单”部分。 - Ybarra
请查看如何创建MCVE(如何创建最小完整可验证示例?)或SSCCE(简短,自包含,正确的示例)-两个名称和链接代表同一个基本想法。您应该能够将代码缩减到主程序管理选项的部分,并在选项处理代码后创建一个循环,以打印其他参数。您应该能够在大约30行左右完成它,可能更少。您还可以在SO上搜索类似的问题;我相信有很多这样的问题。 - Jonathan Leffler
刚刚进行了一次编辑。感谢回复。 - Ybarra
谢谢@JonathanLeffler,最后一个链接帮了很大的忙! - Ybarra
显示剩余2条评论
4个回答

5

如果您使用合理符合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;
}

Compilation

$ 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)
$

如果非可选参数在可选参数之前列出,这个方法还能正常工作吗?@JonathanLeffler - Ybarra
@Ybarra:这取决于您使用的getopt()版本。 POSIX要求选项出现在非选项参数之前;BSD、Solaris、AIX和HP-UX也是如此,据我所知。 GNU getopt()getopt_long()则不会(除非您设置了环境变量POSIXLY_CORRECT)。我可能是少数人,但我不喜欢GNU的行为,也不经常使用它。在以前的工作中,我设置了POSIXLY_CORRECT,并设法破坏了其他人依赖其未设置的脚本。在我看来,这很恶劣(或者说很粗心)。 - Jonathan Leffler

0

如果您无法使用getopt()或其他可以为您完成繁重工作的函数,则可能的策略是:

创建新变量myargc、myargv,并将argc和argv复制到它们中。

编写处理成对参数(如“-n 300000”或“-p page.txt”)的函数。通过引用将myargc和myargv传递给这些函数。每个这样的函数返回与参数相关联的值(例如300000或page.txt),如果找到,则返回无效值(例如-1或“”)。在任何情况下,该函数都会从myargv中删除两个项目,并将myargc减2。

如果您还有一些仅为单个标志的参数,请为这些参数编写函数,返回布尔值指示是否找到了标志,从myargv中删除标志,并将myargc减1。(即使trace_file不是可选的,也可以以这种方式处理它。我假设trace_file只是一个标志,与其后面的8无关。)

首先为每个可选参数调用函数。


0

我认真考虑了一下,发现getopt没有简单的方法来返回多个参数。我曾经想过定义“y::”,但是已经放弃了。有以下几种选择:

1)使用两个选项y和Y,一个用于每个int,另一个用于捕获当y被定义而Y未定义时的异常布尔标志。

2)将像y这样复杂的选项从getopt循环中排除。一旦getopt处理完选项并整理好参数,预处理这些参数以捕获-y操作数,并在处理参数时跳过-y及其操作数。

3)在*nix命令中,更常见的做法是将多个值作为单个参数提供,该参数本身是一个逗号分隔的值列表。通过将“y:”添加到您的getopt处理中来实现此目的。它指向的字符串需要解析为字符串A、B中的2个标记。


0
如果无法使用getopt()或其他可以为您完成繁重工作的函数,则一种可能的策略是:
  • 创建新变量myargc,myargv,并将argc和argv复制到它们中。

  • 编写处理成对参数(如“-n 300000”或“-p page.txt”)的函数。将myargc和myargv通过引用传递给这些函数。每个这样的函数返回与参数相关联的值(例如300000或page.txt),如果找到,则返回无效值(例如-1或“”)。在任何情况下,该函数都会从myargv中删除两个项目,并将myargc减少2。

  • 如果您还有一些仅为单个标志的参数,请编写相应的函数,返回布尔值指示是否找到了该标志,从myargv中删除该标志,并将myargc减少1。(即使trace_file不是可选的,也可以以这种方式处理它。我假设trace_file只是一个标志,与其后面的8无关。)

  • 首先为每个可选参数调用函数。在您调用它们之后留在myargc和myargv中的内容应该只是您的必需参数,您可以像通常一样处理它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接