在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++中,常见的命令行处理方法有以下几种:
- 使用C库getopt()函数,处理短选项 的 命令行参数,如-h -d等。
- 使用getopt_long()函数,处理长选项和短选项 的命令行参数,如 –help等。
- 用户自己根据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.youkuaiyun.com/qq_33850438/article/details/80172275