windows上使用getopt和getopt_long

  参考资料:

  https://www.cnblogs.com/chenliyang/p/6633739.html

  https://www.cnblogs.com/qingergege/p/5914218.html

  https://blog.csdn.net/huangxiaohu_coder/article/details/7475156

  三则参考资料已经将getopt、getopt_long和getopt_long_only的用法写的非常详尽,有珠玉在前,我也不打算再多讲用法了。这篇文章主要讲解一下如何在windows上使用getopt,以及分析一个比较实用的使用案例。

  我们知道getopt和getopt_long主要还是用在Linux操作系统中,在windows上如果你使用#include <getopt.h>是会报错的,所以有人已经将源码迁移修改好供我们使用:https://github.com/Chunde/getopt-for-windows,只要在项目中手动加入源文件即可!

  下面是案例部分,主要探讨一个程序的规范性写法(人性化!),希望对读者有所启发:

  1. 首先,我们定义一个函数,用来打印程序的使用方法:

void usage(const char* progname) {
    printf("Usage: %s [options] scenename\n", progname);
    printf("Valid scenenames are: rgb, rgby, rand10k, rand100k, biglittle, littlebig, pattern,\n"
        "                      bouncingballs, fireworks, hypnosis, snow, snowsingle\n");
    printf("Program Options:\n");
    printf("  -r  --renderer <cpuref/cuda>  Select renderer: ref or cuda (default=cuda)\n");
    printf("  -s  --size  <INT>             Rendered image size: <INT>x<INT> pixels (default=%d)\n", DEFAULT_IMAGE_SIZE);
    printf("  -b  --bench <START:END>       Run for frames [START,END) (default=[0,1))\n");
    printf("  -c  --check                   Check correctness of CUDA output against CPU reference\n");
    printf("  -i  --interactive             Render output to interactive display\n");
    printf("  -f  --file  <FILENAME>        Output file name (FILENAME_xxxx.ppm) (default=output)\n");
    printf("  -?  --help                    This message\n");
}

  注意这个函数的参数是progname,联想到argv[0]不就正是程序的全名吗?用的时候传递argv[0]即可。

  再来看这个usage的写法,它打印了短选项和等价的长选项的用法!最后输出的结果如下:

  2. 然后我们定义一个结构体,在后面这个结构体会被getopt_long()解析(注意常用的是getopt_long,因为它同时支持长短选项)。

    int opt;
    static struct option long_options[] = {
        {"help",        0, 0,  '?'},
        {"check",       0, 0,  'c'},
        {"bench",       1, 0,  'b'},
        {"interactive", 0, 0,  'i'},
        {"file",        1, 0,  'f'},
        {"renderer",    1, 0,  'r'},
        {"size",        1, 0,  's'},
        {0 ,0, 0, 0}
    };

  为什么这个结构长这个样子?其中一则参考资料给出了解释,记录如下:

struct option {
const char  *name;       /* 参数名称 */
int          has_arg;    /* 指明是否带有参数 */
int          *flag;      /* flag=NULL时,返回value;不为空时,*flag=val,返回0 */
int          val;        /* 用于指定函数找到选项的返回值或flag非空时指定*flag的值 */
}; 

 

has_arg  指明是否带参数值,其数值可选:
no_argument         表明长选项不带参数,如:--name, --help
required_argument  表明长选项必须带参数,如:--prefix /root或 --prefix=/root
optional_argument  表明长选项的参数是可选的,如:--help或 –prefix=/root,其它都是错误

  所以最终这个结构体可能会长这个样子(与usage对应):

    static struct option long_options[] = {
        {"help",        0, 0,  '?'},
        {"check",       0, 0,  'c'},
        {"bench",       1, 0,  'b'},
        {"interactive", 0, 0,  'i'},
        {"file",        1, 0,  'f'},
        {"renderer",    1, 0,  'r'},
        {"size",        1, 0,  's'},
        {0 ,0, 0, 0}
    };

  或者这个样子(用到了预定义的参数):

    static struct option long_options[] =
    {  
        {"reqarg", required_argument,NULL, 'r'},
        {"optarg", optional_argument,NULL, 'o'},
        {"noarg",  no_argument,         NULL,'n'},
        {NULL,     0,                      NULL, 0},
    }; 

  3. 万事俱备了,直接进入重头戏吧,即调用getopt_long

    while ((opt = getopt_long(argc, argv, "b:f:r:s:ci?", long_options, NULL)) != EOF) {

        switch (opt) {
        case 'b':
            if (sscanf(optarg, "%d:%d", &benchmarkFrameStart, &benchmarkFrameEnd) != 2) {
                fprintf(stderr, "Invalid argument to -b option\n");
                usage(argv[0]);
                exit(1);
            }
            break;
        case 'i':
            interactiveMode = true;
            break;
        case 'c':
            checkCorrectness = true;
            break;
        case 'f':
            frameFilename = optarg;
            break;
        case 'r':
            if (std::string(optarg).compare("cuda") == 0) {
                useRefRenderer = false;
            }
            else if (std::string(optarg).compare("cpuref") == 0) {
                useRefRenderer = true;
            }
            else {
                fprintf(stderr, "ERROR: Unknown renderer type: %s\n", optarg);
                usage(argv[0]);
                return 1;
            }
            break;
        case 's':
            imageSize = atoi(optarg);
            break;
        case '?':
        default:
            usage(argv[0]);
            return 1;
        }
    }

  从循环中的switch我们看出,这个函数的奥秘就在于:“使用字符串和结构体定义规则,使用规则进行分叉”!具体的用法参看参考资料,这里只介绍这种好的写法。相信这个例子胜过一大段解释!

posted @ 2020-12-04 00:10  思念殇千寻  阅读(597)  评论(0编辑  收藏  举报