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

      注意这个函数的参数是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
    ");
                    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
    ", optarg);
                    usage(argv[0]);
                    return 1;
                }
                break;
            case 's':
                imageSize = atoi(optarg);
                break;
            case '?':
            default:
                usage(argv[0]);
                return 1;
            }
        }
    

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

  • 相关阅读:
    ASP.NET动态生成控件
    WGCLOUD如何禁用指令下发功能
    C#基于NAudio工具对Wav音频文件剪切(限PCM格式)
    C#多线程与多任务
    我的JQuery插件 Confirmer
    我的JQuery插件 submenu
    关于jQuery在asp.net中使用ajax的探讨
    发布jQuery表单验证插件 JQuery.validator.js
    TreeView递归绑定地区列表
    Uploadify(JQuery上传插件)在asp.net中使用例子
  • 原文地址:https://www.cnblogs.com/chester-cs/p/14081426.html
Copyright © 2020-2023  润新知