C/C++ 添加命令行 参数选项

在linux下使用gcc/g++编译代码时,大家都用过类似这样一条指令:gcc helloworld.c -o helloworld.out; 这条指令中的-o就是命令行的选项,而后面的helloworld.out就是-o选项所携带的参数。

命令行参数可以分为两类,一类是短选项,一类是长选项,短选项在参数前加一杠"-",长选项在参数前连续加两杠"--",如terminal下输入man ls(ls 命令参数)所示,其中-a,-A,-b都表示短选项,--all,--almost-all, --author都表示长选项。其中 -a和--all的效果是一样的,所以列在了一起。

对于gcc/g++编译出来的可执行文件,在执行它的时候也可能会需要一些命令行选项,比如./ helloworld.out -h。那么怎么在我们的C/C++代码中支持命令行参数,并根据获取到的参数值来进行代码分支的选择呢。

C/C++程序执行的入口函数int main(int argc, char* argv[])中,argc (argument counter)等于命令行参数个数(比如helloworld.out -h,argc的值等于2),argv (argument value) 中存储的则是命令行参数的值。

C/C++中,常见的命令行处理方法有以下几种:

  1. 使用C库getopt()函数,处理短选项 的 命令行参数,如-h -d等。
  2. 使用getopt_long()函数,处理长选项和短选项 的命令行参数,如 –help等。
  3. 用户自己根据argc和argv进行命令行参数处理。 

getopt()函数

函数原型 :  int getopt(int argc,char * const argv[ ],const char * optstring);

在头文件  #include <unistd.h>  中定义

getopt()只能用来解析短选项: -d 100,不能解析长选项:--prefix

char *optarg:如果有参数,则包含当前选项参数字符串

int optind:opt index,argv的当前索引值。当getopt函数在while循环中使用时,剩下的字符串为操作数,下标从optind到argc-1。

int opterr:这个变量非零时,getopt()函数为“无效选项”和“缺少参数选项,并输出其错误信息。

关于getopt的返回值,如果选项成功找到,返回选项字母;如果所有命令行选项都解析完毕,返回 -1;如果遇到选项字符不在 optstring 中,返回字符 '?';如果遇到丢失参数,那么返回值依赖于 optstring 中第一个字符,如果第一个字符是 ':' 则返回':',否则返回'?'并提示出错误信息。

"ab:c:de::",是一个短选项字符串, optstring。对应到命令行就是-a ,-b ,-c ,-d, -e 。一个冒号就表示前面这个选项必须带有参数,但是这个参数可以和选项连在一起写,也可以用空格隔开,比如-b123 和-b   123(中间有空格) 都表示123是-b的参数;两个冒号的就表示这个选项的参数是可选的,即可以有参数,也可以没有参数,但要注意有参数时,参数与选项之间不能有空格(有空格会报错的哦),这一点和一个冒号时是有区别的。

#include <unistd.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
    int ch;
    printf("\n\n");
    printf("argc:%d \n",argc);
    printf("optind:%d, opterr: %d\n",optind,opterr);
    printf("--------------------------\n");
    while ((ch = getopt(argc, argv, "ab:c:de::")) != -1)
    {
        printf("opt index: %d\n", optind);
        switch (ch) 
        {
            case 'a':
                    printf("HAVE option: -a\n\n");   
                    break;
            case 'b':
                    printf("HAVE option: -b\n"); 
                    printf("The argument of -b is %s\n\n", optarg);
                    break;
            case 'c':
                    printf("HAVE option: -c\n");
                    printf("The argument of -c is %s\n\n", optarg);
                    break;
            case 'd':
                printf("HAVE option: -d\n");
                    break;
            case 'e':
                printf("HAVE option: -e\n");
                printf("The argument of -e is %s\n\n", optarg);
                break;
            case '?':
                    printf("Unknown option: %c\n",(char)optopt);
                    break;
        }
    }
}

 

getopt_long

函数原型 :  int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex); 参数optstring 为短选项命令字符串。

在头文件#include <getopt.h>中定义。getopt.h中还定义了一些相关的结构体,如option。

// getopt.h source code   /usr/include
// option 是在getopt.h 中定义的一个struct, no_argument 也是在其中定义的
struct option {
const char  *name;       /* 参数名称 */
int          has_arg;    /* 指明是否带有参数 */
int          *flag;      /* flag=NULL时,返回value;不为空时,*flag=val,返回0 */
int          val;        /* 用于指定函数找到选项的返回值或flag非空时指定*flag的值 */
};

  (1)name:表示选项的名称,比如daemon,dir,out等。

  (2)has_arg:表示选项后面是否携带参数。该参数有三个不同值,如下:

           a: no_argument(或者是0)时 ——参数后面不跟参数值,eg: --version,--help

           b: required_argument(或者是1)时 ——参数输入格式为:--参数 值 或者 --参数=值。eg:--dir=/home

           c: optional_argument(或者是2)时  ——参数输入格式只能为:--参数=值

  (3)flag:这个参数有两个意思,空或者非空。

           a:如果参数为空NULL,那么当选中某个长选项的时候,getopt_long将返回val值。 eg,可执行程序 --help,getopt_long的返回值为h.             

           b:如果参数不为空,那么当选中某个长选项的时候,getopt_long将返回0,并且将flag指针参数指向val值。 eg: 可执行程序 --http-proxy=127.0.0.1:80 那么getopt_long返回值为0,并且lopt值为1。

如下,为一个getopt_long的示例,其中,参数"abc:d:hn:m:"中的abcdh 与struct option t_long_options[]中的一一对应,这样就达到了短选项和长选项 效果的一致。nm则只有短选项,verbose和file只有长选项。verbose和file选项的val都为0,这是被允许的,此时getopt_long的最后一个参数int *longindex就不能设置为NULL,如示例中的t_option_index。

EXIT_FAILURE和EXIT_SUCCESS是C语言头文件库中定义的一个符号常量,且都可以作为exit()的参数来使用。EXIT_FAILURE表示没有成功地执行一个程序;EXIT_SUCCESS表示成功地执行一个程序。

atoi (表示 ascii to integer)是把字符串转换成整型数的一个函数。

#include <stdio.h>     /* for printf */
#include <stdlib.h>    /* for exit */
#include <getopt.h>
#include <iostream> 

using namespace std;

void print_usage(const char* name)
{
    cout<<"\nUsage: " << name << " [options]" << std::endl
        << "Options:" << std::endl
        << "  -a, --add          add all file \n"
        << "  -b, --append       append all file \n"
        << "  -c, --create       create a string (must have a string argument) \n"
        << "  -d, --delete       delete a number (must have a number argument) \n"
        << "  -h, --help         print this help info \n" 
        << "  -n                 new a file (must have a string argument) \n"
        << "  -m                 new a number (must have a number argument) \n"
        << "  --verbose          verbose  \n"
        << "  --file             file (must have a argument) \n"        
        << "\n"
        << std::endl;
}

int main(int argc, char **argv)
{
    int t_opt;
    int t_option_index = 0;
    static struct option t_long_options[] = {
        {"add",     no_argument,       0, 'a'},
        {"append",  no_argument,       0, 'b'},
        {"create",  required_argument, 0, 'c'},
        {"delete",  required_argument, 0, 'd'},
        {"help",    no_argument,       0, 'h'},
        {"verbose", no_argument,       0,  0 },
        {"file",    required_argument, 0,  0 },
        {0,         0,                 0,  0 }
    };
 
    while( (t_opt = getopt_long(argc, argv, "abc:d:hn:m:",t_long_options, &t_option_index) ) != -1)
    {
        switch (t_opt)
        {
            default:
            case '?':
            case 'h':
                print_usage(argv[0]);
                return EXIT_FAILURE;
            case 'a':
                printf("HAVE option: -a\n\n");break;
            case 'b':
                printf("HAVE option: -b\n\n"); break;
            case 'c':
                printf("HAVE option: -c\n");
                printf("The argument of -c is %s\n\n", optarg);
                break;
            case 'd':
                printf("HAVE option: -d\n");
                printf("The argument of -d is %d\n\n", atoi(optarg));
                break;
            case 'n':
                printf("HAVE option: -n\n");
                printf("The argument of -n is %s\n\n", optarg);
                break;
            case 'm':
                printf("HAVE option: -m\n");
                printf("The argument of -m is %d\n\n", atoi(optarg));
                break;
            case 0:
                printf("option %s", t_long_options[t_option_index].name);
                if (optarg)
                    printf(" with arg %s", optarg);
                printf("\n");
                break;
        }
    }

   exit(EXIT_SUCCESS);
}

 

自定义处理命令行参数

 

除了getopt和getopt_long,用户也可以自行对命令行参数进行处理,如下示例。

#include <stdio.h>     /* for printf */
#include <stdlib.h>
#include <string>
#include <iostream> 

using namespace std;

void print_usage(const char* name)
{
    cout<<"\nUsage: " << name << " [options]" << std::endl
        << "Options:" << std::endl
        << "  -a, --add          add all file \n"
        << "  -b, --append       append all file \n"
        << "  -c, --create       create a string (must have a string argument) \n"
        << "  -d, --delete       delete a number (must have a number argument) \n"
        << "  -h, --help         print this help info \n"   
        << "\n"
        << std::endl;
}

int main(int argc, char ** argv)
{
    if (argc<2) 
    {
        print_usage(argv[0]);
        return 1;
    }

    for (int i=1; i<argc; i++) 
    {
        std::string t_arg = std::string(argv[i]);
        if (t_arg == "-h" || t_arg == "--help") 
        {
            print_usage(argv[0]);
            return 0;
        } 
        else if (t_arg == "-a" || t_arg == "--add")
        {
            printf("HAVE option: -a\n\n");
        }
        else if (t_arg == "-b" || t_arg == "--append")
        {
            printf("HAVE option: -b\n\n");
        }
        else if (t_arg == "-c" || t_arg == "--create")
        {
            printf("HAVE option: -c\n\n");
            if( (i+1) < argc)
            {
                printf("The argument of -c is %s\n\n", argv[++i]);
            }
            else
            {
                printf("Option -c requires one argument \n");
                print_usage(argv[0]);
            }
        }
        else if (t_arg == "-d" || t_arg == "--delete")
        {
            printf("HAVE option: -d\n\n");
            if( (i+1) < argc)
            {
                printf("The argument of -d is %d\n\n", atoi(argv[++i]) );
            }
            else
            {
                printf("Option -d requires one argument \n");
                print_usage(argv[0]);
            }
        }
        else
        {
            printf("Option %s is not available \n", argv[i] );
        }
    }
    exit(EXIT_SUCCESS);
}

 

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

https://blog.csdn.net/qq_33850438/article/details/80172275

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

123axj

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值