在 C/C++ 中处理命令行标志

Posted

技术标签:

【中文标题】在 C/C++ 中处理命令行标志【英文标题】:Handling command line flags in C/C++ 【发布时间】:2013-01-22 04:13:09 【问题描述】:

我正在寻找关于标志是什么的非常简单的解释/教程。我知道标志工作表明命令要做什么。例如:

rm -Rf test

我知道 rm 命令将删除测试文件夹,并且 -Rf 标志将强制命令不仅删除文件夹,还删除其中的文件。

但是,读取/编译的标志在哪里???什么处理标志?例如,我可以编写自己的 C/C++ 程序并指定不同的标志,以便程序执行不同的操作吗?我希望我问的是正确的问题。如果没有,请告诉我。

【问题讨论】:

【参考方案1】:

在 C 级别,程序的命令行参数出现在 main 函数的参数中。例如,如果你编译这个程序:

#include <stdio.h>
int main(int argc, char **argv)

    int i;
    for (i = 0; i < argc; i++)
        printf("argv[%d] = %s\n", i, argv[i]);
    return 0;
 

并使用与您的示例“rm”命令相同的参数调用它,您会得到:

$ ./a.out -Rf test
argv[0] = ./a.out
argv[1] = -Rf
argv[2] = test

如您所见,argv 中的第一个条目是程序本身的名称,其余的数组条目是命令行参数。

操作系统根本不关心参数是什么;由您的程序来解释它们。但是,它们的工作方式有一些约定,其中最重要的是:

参数分为选项非选项。选项以破折号开头,非选项不用。 选项,顾名思义,应该是可选的。如果您的程序需要一些命令行参数来执行任何有用的操作,那么这些参数应该是非选项(即它们应该以破折号开头)。 选项可以进一步分为选项,即一个短划线后跟一个字母(-r-f)和选项,这是两个破折号后跟一个或多个破折号分隔的单词(--recursive--frobnicate-the-gourds)。短选项可以组合成一个参数 (-rf),只要它们都不带参数(见下文)。 选项本身可能带有参数。 short 选项 -x 的参数是 argv 条目的剩余部分,或者如果该条目中没有其他文本,则为下一个 argv 条目 是否以破折号开头。 long 选项的参数以等号开头:--output=outputfile.txt。 如果可能的话,不同选项(及其参数)的相对顺序应该没有明显的影响。 特殊选项-- 的意思是“不要将命令行上此点之后的任何内容视为选项,即使它看起来像一个选项。”例如,您可以通过键入 rm -- -f 来删除名为“-f”的文件。 特殊选项- 表示“读取标准输入”。 按照惯例保留了许多短选项字母:最重要的是 -v = 冗长 -q = 安静 -h = 打印一些帮助文本 -o file = 输出到 file -f = force(不提示确认危险动作,直接执行)

有很多库可以帮助您解析命令行参数。其中最可移植但也最受限制的是getopt,它内置于当今大多数系统的C 库中。我建议您阅读 GNU argp 的所有文档,即使您不想使用那个特定的文档,因为它会进一步教育您了解约定。

还值得一提的是,通配符扩展 (rm -rf *) 在您的程序被调用之前完成。如果您在仅包含二进制文件及其源代码的目录中以./a.out * 的身份运行上述示例程序,您将获得

argv[0] = ./a.out
argv[1] = a.out
argv[2] = test.c

【讨论】:

精彩的描述!谢谢。【参考方案2】:

这个简单的程序应该演示传递给程序的参数(包括程序名称本身。)

解析、解释和使用这些参数取决于程序员(你),尽管有libraries available to help:

int main(int argc, char* argv[])

    int i;
    for(i=0; i<argc; ++i)
       printf("Argument %d : %s\n", i, argv[i]);
    
    return 0;


如果你把这个程序编译成a.out,并运行为:

prompt$>  ./a.out ParamOne ParamTwo -rf x.c

你应该看到输出:

Argument 0 : a.out
Argument 1 : ParamOne
Argument 2 : ParamTwo
Argument 3 : -rf
Argument 4 : x.c

【讨论】:

【参考方案3】:

实际上你可以编写自己的 C++ 程序,它接受这样的命令行参数:

int main(int argc, char* argv[])

变量 argc 将包含参数的数量,而 char* 将包含参数本身。

您可以像这样调度参数:

for (int i = 1; i < argc; i++)
  
    if (i + 1 != argc)
    
        if (strcmp(argv[i], "-filename") == 0) // This is your parameter name
                         
            char* filename = argv[i + 1];    // The next value in the array is your value
            i++;    // Move to the next flag
        
    

【讨论】:

在第 3 行,您在比较指针,而不是字符串...应该是:if ( strcmp( argc[i], "-filename") == 0) 【参考方案4】:

在您自己的 C 程序中,您可以以任何您认为合适的方式处理命令行选项。 C 中的命令行参数以字符串形式出现在 main(int argc, char *argv[]) 方法的参数中。

如果您想以类似于大多数 UNIX 命令的方式处理命令行参数,您可能正在寻找的函数是 getopt()

祝你好运!

【讨论】:

getopt 非常古老。 argp_parse 是一个合理的替代品,并且有许多可用的选项解析库(例如libpopt)。【参考方案5】:

最简单的方法是像这样写你的main()

int main(int argc, char* argv[]) ...

然后在那个主要的决定命令行参数或“标志”会发生什么。您在 argv 中找到它们,它们的编号是 argc。

【讨论】:

【参考方案6】:

标志是传递到程序主入口点的参数。例如,在 C++ 程序中,您可以拥有

int main(int arc, char* argv[])
return 0;

你的弧是传入的参数#,指针给你实际参数的列表。所以对于

rm -Rf test

argc 将是 3,而 argv 数组将包含您的参数。注意 argc >= 1 因为程序名称本身很重要 (rm)。 -RF 是您的第二个参数,而 test 是您的第三个参数。

因此,每当您在 unix 中键入命令时,您实际上是在执行程序并向它们传递它们所操作的参数。

如果您真的对 unix 操作系统感兴趣,您应该查看 fork 以及它们的工作原理。不过,这可能会让新手很困惑,所以只有当您真正对操作系统以及程序的执行方式感兴趣时。

【讨论】:

【参考方案7】:

GNU libc 很可能在您的系统上可用,它有一个名为 getopt 的库,可用于以合理的方式解析选项。下面链接的文档中有一些示例可以帮助您入门。

http://www.gnu.org/software/libc/manual/html_node/Getopt.html#Getopt

【讨论】:

以上是关于在 C/C++ 中处理命令行标志的主要内容,如果未能解决你的问题,请参考以下文章

如何在没有“标志”包的情况下在 Go 中获取命令行参数?

宏和 lib 文件的 devenv 命令行选项

如何在 Python3 中添加带有标志的命令行参数?

在bash中检查命令行标志的正确方法

如何在erl中为单个标志设置多个命令行参数

用于禁用 Chrome 中所有类型缓存的命令行标志