【问题标题】:Parsing optional command line arguments in C在 C 中解析可选的命令行参数
【发布时间】:2015-07-06 17:22:27
【问题描述】:

我有一个接受可选参数的程序。必要的参数是文件和整数(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]));
}

但这只有在没有输入可选参数时才有效。

【问题讨论】:

  • 到目前为止你写的代码是什么样子的?
  • 要发布的内容很多。该程序适用于学校的作业,我们正在模拟地址分页。所以,我问的问题实际上只是我程序的一个“简单”部分
  • 但是你想看什么?我真的只是想知道如何获得'trace_file'之后的整数,无论​​用户如何在命令行上输入它们(例如./main trace_file 8 7 4 –n 3000000 –p page.txt)
  • 了解如何创建 MCVE (How to create a Minimal, Complete, and Verifiable Example?) 或 SSCCE (Short, Self-Contained, Correct Example) — 两个名称和链接用于相同的基本思想。您应该能够将代码简化为管理选项的主程序部分,并在打印其他参数的选项处理代码之后创建一个循环。您应该能够在大约 30 行内完成,可能更少。您也可以在 SO 上搜索类似的问题;有很多,我敢肯定。
  • 刚刚进行了编辑。感谢您的回复。

标签: c command-line getopt


【解决方案1】:

如果您不能使用 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 无关。)

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

【讨论】:

    【解决方案2】:

    如果您不能使用 getopt() 或其他为您完成工作的函数,那么可能的策略是:

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

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

    • 1234563方式,即使它不是可选的。我假设 trace_file 只是一个标志,与它后面的 8 无关。)
    • 首先为每个可选参数调用函数。调用 myargc 和 myargv 后剩下的内容应该只是您需要的参数,您可以像往常一样处理它们。

    【讨论】:

      【解决方案3】:

      如果您使用合理的符合 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)
      $
      

      【讨论】:

      • 如果非可选参数列在可选参数之前,这是否会以同样的方式工作? @JonathanLeffler
      • @Ybarra:这取决于您使用的getopt() 的版本。 POSIX 要求选项出现在非选项参数之前; BSD、Solaris、AIX 和 HP-UX、AFAICR 也是如此。 GNU getopt() and getopt_long() 不这样做(除非您设置环境变量 POSIXLY_CORRECT)。我可能是少数,但我不喜欢 GNU 的行为并且不经常使用它。在之前的工作中,我设置了 POSIXLY_CORRECT — 并设法破坏了依赖于它未设置的其他人的脚本。就我而言,这很糟糕(或粗心)。
      【解决方案4】:

      我对此进行了一些思考,并且没有简单的方法让 getopt 返回多个参数。我确实想知道定义“y::”,但已经驳回了这一点。选项是

      1) 有 2 个选项 y 和 Y 对每个 int 使用一个,并使用一个布尔标志来捕获定义 y 但 Y 未定义的异常。

      2) 将像 y 这样的复杂选项排除在 getopt 循环之外。一旦 getopt 处理了选项并改组了参数。预处理这些参数以捕获 -y 操作数和过程参数中的代码以跳过 -y 及其操作数

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

      【讨论】:

        猜你喜欢
        • 2017-08-31
        • 2013-03-07
        • 1970-01-01
        • 1970-01-01
        • 2010-10-26
        相关资源
        最近更新 更多