C:以正确的方式解析选项

Posted

技术标签:

【中文标题】C:以正确的方式解析选项【英文标题】:C : Parsing options the right way 【发布时间】:2012-11-28 22:48:34 【问题描述】:

我正在尝试解析 C 程序中的两个选项。

程序是这样调用的:

./a.out [OPTIONS] [DIRECTORY 1] [DIRECTORY 2]

程序同步两个目录并有两个选项。 (-r) 用于递归同步(文件夹内的文件夹),(-n) 用于将文件从本地复制到远程,以防远程中不存在。

Options are:
-r : recursive
-n : copy file if it doesn't exist in remote folder

呼唤:

./a.out -r D1 D2

将递归同步从D1D2 的所有文件和目录。 D1 中存在且D2 中不存在的文件将被忽略。

然后调用:

./a.cout -rn D1 D2

会做同样的事情,但D1 中存在的文件和D2 中不存在的文件被复制到D2

问题是调用./a.out -rn 与调用./a.out -nr 不同,./a.out -r -n 也不起作用,因为(-n) 不是D1

这是我实现 main 的方法。

int main(int argc, char** argv) 
  int next_option = 0;
  const char* const short_options = "hrn:";

  const struct option long_options[] = 
     "help",      0, NULL,  'h' ,
     "recursive", 1, NULL,  'r' ,
     "new", 1, NULL,  'n' ,
     NULL,        0, NULL,  0   
  ;

  int recursive = 0;
  int new = 0;

  do 
    next_option = getopt_long(argc, argv, short_options, long_options, NULL);

    switch(next_option) 
      case 'r':
        recursive = 1;
        break;

      case 'n':
        new = 1;
        break;

      case 'h':
        print_help();
        return 0;

      case -1:
        break;

      default:
        print_help();
        return -1;
    

   while(next_option != -1);

  sync(argv[2], argv[3], recursive, new);

  return EXIT_SUCCESS;

【问题讨论】:

-rn-nr 有什么不同?您的实现表明两者应该是等价的。 我向你保证,结果是不一样的。 -rn = 递归:1,新:1 ,-nr = 递归:0,新:1 我还建议您不要在代码中使用 C++ 关键字(如 new)。只要您使用 C 编译器,它就可以工作,但如果您将来决定切换到 C++,它就不可移植。 那么,问题在于-rn-nr 相同,而您不希望它们相同?或者,问题是 getopt 以某种方式读错了? 【参考方案1】:

这里有两个(潜在的)问题:

    您的短选项字符串中有一个杂散的:。这使得-n 可以选择吞下任何后续r。您还可以设置长选项来接受强制参数。

    您以不灵活的方式硬编码了参数编号,并且您没有测试它们是否存在。

试试这个:

int main(int argc, char** argv) 
  int next_option = 0;
  const char* const short_options = "hrn";
  extern int optind;

  const struct option long_options[] = 
     "help",      no_argument, NULL,  'h' ,
     "recursive", no_argument, NULL,  'r' ,
     "new",       no_argument, NULL,  'n' ,
     NULL,        no_argument, NULL,  0   
  ;

  int recursive = 0;
  int new = 0;

  do 
    next_option = getopt_long(argc, argv, short_options, long_options, NULL);

    switch(next_option) 
      case 'r':
        recursive = 1;
        break;

      case 'n':
        new = 1;
        break;

      case 'h':
        print_help();
        return 0;

      case -1:
        break;

      default:
        print_help();
        return -1;
    

   while(next_option != -1);

  if (optind + 1 >= argc)
    return -1;

  sync(argv[optind], argv[optind+1], recursive, new);

  return EXIT_SUCCESS;

【讨论】:

【参考方案2】:

使用诸如-r -n 之类的命令行的问题是因为您在对sync 的调用中硬编码了索引。你不应该那样做。

如果您阅读getopt_long 手册页(当您遇到函数问题时总是这样做!)然后您会注意到这一行:

如果没有更多选项字符,getopt() 返回 -1。那么 optind 是第一个 argv 元素的 argv 中不是选项的索引。

仔细阅读第二句话。

【讨论】:

确实如此,但实际上并不是 OP 的问题。请注意,他从来没有说过-r -n,他说的是-rn,在那种情况下,代码是错误的但没有损坏。 @ams 在-rn-nr 之后,OP 确实说-r -n 也存在问题。 哦,是的,因为换行,我没有看到。我的错。

以上是关于C:以正确的方式解析选项的主要内容,如果未能解决你的问题,请参考以下文章

在启动时以编程方式为 5 个选项卡栏项目设置选项卡栏标题,其中 4 个嵌入在导航控制器中,1 个没有。目标 C

在 C 中处理参数前后的命令行选项

如何将任意选项字符串解析为python字典

使用 jquery 以编程方式选择 select2 选项

如何根据 X、Y 坐标以编程方式确定表单上字段的选项卡索引?

ios unwindsegue 没有显示正确的下拉选项