C语言getopt()的8个用法

概况

做 CSAPP 的 CacheLab 的第一个门槛是学习使用 getopt() 函数。它是 Linux 下的函数,Windows 先不考虑了。

查询 getopt 用法的”官方”步骤是看 man 手册:

man 3 getopt

C语言getopt()的8个用法

不过这手册看的让人头晕,还是写几个例子,分解开来逐一击破吧!
写了8个例子,每个例子都有对应注释和示例用法;也可以在 main 函数中把 argc 和 argv 传递过去,分别调用和尝试!


int main(int argc, char** argv)
{
    //printf("opterr = %d\n", opterr);

    //opt_example1(argc, argv);
    //opt_example2(argc, argv);
    //opt_example3(argc, argv);
    //opt_example4(argc, argv);
    //opt_example5(argc, argv);
    //opt_example6(argc, argv);
    //opt_example7(argc, argv);
    opt_example8(argc, argv);

    return 0;
}

例子1

#include
#include
#include
#include

// -a 选项后面一定要有参数,参数和选项之间可以有空格,也可以没空格。解析出的参数放在 optarg 变量里。
// examples:
// ./a.out -a 6
// ./a.out -a6
// ./a.out -a s
// 参数也可以用引号包裹起来,这样可以包含空格.

// ./a.out -a "s b"
// ./a.out -a"s b"
void opt_example1(int argc, char** argv)
{
    const char* optstr = "a:";
    char ch;
    while ( (ch = getopt(argc, argv, optstr)) != -1 )
    {
        switch (ch) {
            case 'a':
                printf("have option: -a\n");
                printf("the argument of -a is %s\n", optarg);
                break;
        }
    }
}

例子2

// -b 选项后面可以有参数,也可以没有参数。但是有参数情况下,必须有空格。若没有空格,得到的参数是 null
// examples:
// ./a.out -b
// ./a.out -b hello
void opt_example2(int argc, char** argv)
{
    const char* optstr = "b::";
    char ch;
    while ( (ch = getopt(argc, argv, optstr)) != -1 )
    {
        switch (ch) {
            case 'b':
                printf("have option: -b\n");
                printf("the argument of -b is %s\n", optarg);
                break;
        }
    }
}

例子3

// -c 选项后面不能有参数。如果有参数,会被当成别的选项. 打印 optarg 得到 null
// examples:
// ./a.out -c
void opt_example3(int argc, char** argv)
{
    const char* optstr = "c";
    char ch;
    while ( (ch = getopt(argc, argv, optstr)) != -1 )
    {
        switch (ch) {
            case 'c':
                printf("have option: -c\n");
                printf("the argument of -c is %s\n", optarg);
                break;
        }
    }
}

例子4

// -c 选项和 -d 选项可以合并
// examples:
// ./a.out -c -d
// ./a.out -d -c
// ./a.out -cd
// ./a.out -dc
void opt_example4(int argc, char** argv)
{
    const char* optstr = "cd";
    char ch;
    while ( (ch = getopt(argc, argv, optstr)) != -1 )
    {
        switch (ch) {
            case 'c':
                printf("have option: -c\n");
                printf("the argument of -c is %s\n", optarg);
                break;
            case 'd':
                printf("have option: -d\n");
                printf("the argument of -d is %s\n", optarg);
                break;
        }
    }
}

例子5

// argv 中不以 "-" 开头的、并且不是跟在选项后面的,不会被 getopt() 解析
// 不被解析意味着, 调用 getopt() 之后会改变 argv 的元素顺序, 被解析的 选项+参数 们 在前,没被解析的在后
// examples:
// ./a.out shenme -a hello -b world
//     新版 argv 会是 ./a.out -a hello -b world shenme
// ./a.out -a hello shenme -b world
//     新版 argv 会是 ./a.out -a hello -b world shenme
// 被解析的选项们的顺序是不会被改变的. 如果没空格,也不会被更细出空格
// ./a.out shenme -b world -a hello
//     新版 argv 会是 ./a.out -b world -a hello shenme
// ./a.out shenme -bworld -a hello
//     新版 argv 会是 ./a.out -bworld -a hello shenme
// 调用 getopt() 后, optind 会指向第一个非选项和参数的位置
void opt_example5(int argc, char** argv)
{
    printf("original argv is:");
    for (int i = 0; i < argc; i++)
    {
        printf(" %s", argv[i]);
    }
    printf("\n");

    char ch;
    const char* optstr = "a:b:c:";
    while( (ch = getopt(argc, argv, optstr)) != -1 )
    {
        switch(ch)
        {
        case 'a':
            break;
        case 'b':
            break;
        }
    }

    printf("after getopt, argv is:");
    for (int i = 0; i < argc; i++)
    {
        printf(" %s", argv[i]);
    }
    printf("\n");

    printf("and now, optind = %d, argv[%d] = %s\n",
        optind, optind, argv[optind]);
}

例子6

// 利用 optind 判断是否输出了指定选项和参数外的参数
// 若只输入了符合 optstr 的 argv, 则 optind 小于 argc
// 若输入了额外的参数, 则 optind 等于 argc
// examples:
// ./a.out -a hello world
//    输出:
// optind = 3, argv[3] = world
// you have entered extra arguments: world
//
// ./a.out -a 0 hello world
//    输出:
// optind = 3, argv[3] = hello
// you have entered extra arguments: hello world
void opt_example6(int argc, char** argv)
{
    char ch;
    const char* optstr = "a:b:c:";
    while( (ch = getopt(argc, argv, optstr)) != -1 )
    {
        switch(ch)
        {
        case 'a':
            break;
        case 'b':
            break;
        }
    }

    printf("optind = %d, argv[%d] = %s\n",
        optind, optind, argv[optind]);

    if (optind < argc)
    {
        printf("you have entered extra arguments:");
        for (int i = optind; i < argc; i++)
        {
            printf(" %s", argv[i]);
        }
        printf("\n");
    }
}

例子7

// argv &#x53EF;&#x80FD;&#x5305;&#x542B; getopt() &#x65E0;&#x6CD5;&#x89E3;&#x6790;&#x7684;&#x9009;&#x9879;&#xFF0C;&#x4E5F;&#x5C31;&#x662F;&#x4E0D;&#x5728; optstr &#x4E2D;&#x7684;&#x9009;&#x9879;
// &#x8FD9;&#x6837;&#x7684;&#x9009;&#x9879;&#xFF0C;&#x5BF9;&#x5E94;&#x5230; getopt() &#x8FD4;&#x56DE; ? , &#x53EF;&#x4EE5;&#x8BBE;&#x7F6E;&#x4E3A;&#x6253;&#x5370;help&#x4FE1;&#x606F;
// examples:
// ./a.out -s
//   &#x8F93;&#x51FA;
// ./a.out: invalid option -- 's'
// Usage: ./a.out -a <a_arg> -b <b_arg>
void opt_example7(int argc, char** argv)
{
    char ch;
    const char* optstr = "a:b:c:";
    while( (ch = getopt(argc, argv, optstr)) != -1 )
    {
        switch(ch)
        {
        case 'a':
            break;
        case 'b':
            break;
        case '?':
            printf("Usage: %s -a <a_arg> -b <b_arg>\n", argv[0]);
        }
    }
}
</b_arg></a_arg></b_arg></a_arg>

例子8

void help_and_die(char* argv0)
{
    printf("Usage: %s [-hv] -s  -E  -b  -t \n", argv0);
    printf("Options:\n");
    printf("  -h         Print this help message.\n");
    printf("  -v         Optional verbose flag.\n");
    printf("  -s    Number of set index bits.\n");
    printf("  -E    Number of lines per set.\n");
    printf("  -b    Number of block offset bits.\n");
    printf("  -t   Trace file.\n");
    printf("\n");
    printf("Examples:\n");
    printf("  linux>  %s -s 4 -E 1 -b 4 -t traces/yi.trace\n", argv0);
    printf("  linux>  %s -v -s 8 -E 2 -b 4 -t traces/yi.trace\n", argv0);

    exit(0);
}

// CSAPP CacheLab 的例子,模拟 csim-ref 的参数解析
void opt_example8(int argc, char* argv[])
{
    const char* optstr = "hvs:E:b:t:";
    char ch;

    bool verbose = false;
    int s = -1;
    int E = -1;
    int b = -1;
    int t = -1;
    while( (ch = getopt(argc, argv, optstr)) != -1 )
    {
        switch (ch)
        {
        case 'h':
            help_and_die(argv[0]);
            exit(0);
            break;
        case 'v':
            verbose = true;
            break;
        case 's':
            s = atoi(optarg);
            break;
        case 'E':
            E = atoi(optarg);
            break;
        case 'b':
            b = atoi(optarg);
            break;
        case 't':
            t = atoi(optarg);
            break;
        case '?':
            help_and_die(argv[0]);
            break;
        }
    }

    if (optind == 1)
    {
        printf("%s: Missing required command line argument\n", argv[0]);
        help_and_die(argv[0]);
    }
}

Original: https://www.cnblogs.com/zjutzz/p/15917181.html
Author: ChrisZZ
Title: C语言getopt()的8个用法

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/535620/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • JavaSE 可变参数的方法重载

    1 /** 2 * 可变参数的方法重载 3 */ 4 class A { 5 public void test(int a, int b) { 6 System.out.print…

    C语言 2023年5月29日
    075
  • C语言switch 第一行不能定义变量的解决办法

    1.case后加一行代码 switch(cmd) { case CMD_A:break; case CMD_B: printf("&#x52A0;&#x4…

    C语言 2023年5月29日
    057
  • c语言-动态内存分配(上课)

    源程序: include //主菜单void menu(){printf(“\n****\n”);printf(“1. 创建单链表\n&#822…

    C语言 2023年5月29日
    051
  • 逆向初级-C语言(二)

    2.1.C语言的汇编表示 c语言代码 int plus(int x,int y) { return 0; } void main() { __asm { mov eax,eax }…

    C语言 2023年5月29日
    048
  • 再次实践用c语言来编写webgl

    当年asm.js出来的时候,emscripten这个工具链还不是很好用,不,是很难用。 尝试以后,被一个helloworld 好几兆吓退了。 webassembly 如今已经发育的…

    C语言 2023年5月29日
    051
  • c语言获取cpu数量

    1、在Linux下获取CPU核数 linux下可以通过linux系统提供的sysconf()来获取当前CPU个数,sysconf在头文件unistd.h中声明。 sysconf函数…

    C语言 2023年5月29日
    087
  • C语言的原码,反码,补码

    1)原码表示 原码表示法是机器数的一种简单的表示法。其符号位用0表示正号,用:表示负号,数值一般用二进制形式表示。设有一数为x,则原码表示可记作[x]原。 例如,X1= +1010…

    C语言 2023年5月29日
    078
  • C#传委托给C语言的函数指针调用问题

    C代码如下: 多次验证发现在C#中传委托给C中的函数指针,如果委托不带参数则都能成功运行,但是委托一带参数不管是int参数还是string参数或者其他参数,都会报” 尝…

    C语言 2023年5月29日
    072
  • Picoc C语言解释器简介,及STM32平台移植工程

    Picoc是google开源代码项目中看到的一个项目,其初衷貌似是要做一个在小的嵌入设备上的C解释器。它的核心代码只有3500行左右,可读性不错,虽然没有实现完整的ISO C标准,…

    C语言 2023年5月29日
    056
  • C语言字符串操作总结大全(超详细)

    1)字符串操作strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strcat(p, p1) 附加字符串 strncat(p, p1, …

    C语言 2023年5月29日
    034
  • C语言字符串处理函数

    ssprintf和sscanf函数的使用总结: 1、前言 我们经常涉及到数字与字符串之间的转换,例如将32位无符号整数的ip地址转换为点分十进制的ip地址字符串,或者反过来。从给定…

    C语言 2023年5月29日
    087
  • JavaSE assert断言的学习

    在Java中,assert关键字是从JAVA SE 1.4 引入的,为了避免和老版本的Java代码中使用了assert关键字导致错误,Java在执行的时候默认是不启动断言检查的(这…

    C语言 2023年5月29日
    059
  • c语言 结构体(二)-上课用

    源程序: //编写一个函数print,输出学生的信息,该数组有5个学生的记录,包括://num, sname, score[3],用主函数输入这些记录,用print函数输出这些记录…

    C语言 2023年5月29日
    065
  • 拓扑排序(一)之 C语言详解

    拓扑排序(Topological Order)是指,将一个有向无环图(Directed Acyclic Graph简称DAG)进行排序进而得到一个有序的线性序列。 这样说,可能理解…

    C语言 2023年5月29日
    059
  • C语言字符串操作总结大全

    转:https://www.cnblogs.com/lidabo/p/5225868.html 1)字符串操作strcpy(p, p1) 复制字符串strncpy(p, p1, n…

    C语言 2023年5月29日
    040
  • Kruskal算法(一)之 C语言详解

    本章介绍克鲁斯卡尔算法。和以往一样,本文会先对克鲁斯卡尔算法的理论论知识进行介绍,然后给出C语言的实现。后续再分别给出C++和Java版本的实现。目录1. 最小生成树2. 克鲁斯卡…

    C语言 2023年5月29日
    058
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球