[整理]getopt()或getopt_long()与optarg
getopt或getopt_long 是一个Linux下面的库函数,作用就是解析命令行的输入。其目的就是减轻程序员自己的负担,可以直接使用系统提供的库函数,方便、高效和更安全地解析命令行的输入。
如果你编写的应用程序中的输入参数很少,就2,3个,那么就可以自己去判断,类似于:
mtd-util中的flash_erase.c中的。
。。。
if (argc > 2)
start = strtol(argv[2], NULL, 0);
else
start = 0;
if (argc > 3)
count = strtol(argv[3], NULL, 0);
else
count = 1;
if(argc > 4)
unlock = strtol(argv[4], NULL, 0);
else
unlock = 0;
。。。
如果选项和参数很多,那么自己去一个个判断,效率就太低了,而且也容易出错,那么就可以利用getopt或getopt_long函数了。
先转帖一些相关知识:
int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
说明:函数中的argc和argv通常直接从main()到两个参数传递而来。optsting是选项参数组成的字符串,如果该字符串里任一字母后有冒号,那么这个选项就要求有参数。下一个参数是指向数组的指针,这个数组是option结构数组,option结构称为长选项表,其声明如下:
struct option {
const char *name;
int has_arg;
int *flag;
int val;
};
结构中的元素解释如下:
const char *name:选项名,前面没有短横线。譬如"help"、"verbose"之类。
int has_arg:描述长选项是否有选项参数,如果有,是哪种类型的参数,其值见下表:
符号常量 数值 含义
no_argument 0 选项没有参数
required_argument 1 选项需要参数
optional_argument 2 选项参数是可选的
int *flag:
如果该指针为NULL,那么getopt_long返回val字段的值;
如果该指针不为NULL,那么会使得它所指向的结构填入val字段的值,同时getopt_long返回0
int val:
如果flag是NULL,那么val通常是个字符常量,如果短选项和长选项一致,那么该字符就应该与optstring中出现的这个选项的参数相同;
最后一个参数:longindex参数一般赋为NULL即可;如果没有设置为NULL,那么它就指向一个变量,这个变量会被赋值为寻找到的长选项在longopts中的索引值,这可以用于错误诊断。
具体用法,给个例子就可以看懂了:
mtd-util中的nandwrite.c :
#include <unistd.h>
#include <getopt.h>
。。。
static const char *standard_input = "-";
static const char *mtd_device, *img;
static int mtdoffset = 0;
static bool quiet = false;
static bool writeoob = false;
static bool autoplace = false;
static bool uboot = false;
static bool markbad = false;
static bool forcejffs2 = false;
static bool forceyaffs = false;
static bool forcelegacy = false;
static bool noecc = false;
static bool pad = false;
static int blockalign = 1; /*default to using 16K block size */
static void process_options (int argc, char * const argv[])
{
int error = 0;
for (;;) {
int option_index = 0;
static const char *short_options = "ab:fjmnopqs:uy";
static const struct option long_options[] = {
{"help", no_argument, 0, 0},
{"version", no_argument, 0, 0},
{"autoplace", no_argument, 0, ‘a’},
{"blockalign", required_argument, 0, ‘b’},
{"forcelegacy", no_argument, 0, ‘f’},
{"jffs2", no_argument, 0, ‘j’},
{"markbad", no_argument, 0, ‘m’},
{"noecc", no_argument, 0, ‘n’},
{"oob", no_argument, 0, ‘o’},
{"pad", no_argument, 0, ‘p’},
{"quiet", no_argument, 0, ‘q’},
{"start", required_argument, 0, ‘s’},
{"uboot", no_argument, 0, ‘u’},
{"yaffs", no_argument, 0, ‘y’},
{0, 0, 0, 0},
};
int c = getopt_long(argc, argv, short_options,
long_options, &option_index);
if (c == EOF) {
break;
}
switch (c) {
case 0:
switch (option_index) {
case 0:
display_help();
break;
case 1:
display_version();
break;
}
break;
case ‘q’:
quiet = true;
break;
case ‘a’:
autoplace = true;
break;
case ‘u’:
uboot = true;
break;
case ‘j’:
forcejffs2 = true;
break;
case ‘y’:
forceyaffs = true;
break;
case ‘f’:
forcelegacy = true;
break;
case ‘n’:
noecc = true;
break;
case ‘m’:
markbad = true;
break;
case ‘o’:
writeoob = true;
break;
case ‘p’:
pad = true;
break;
case ‘s’:
mtdoffset = strtol (optarg, NULL, 0);
break;
case ‘b’:
blockalign = atoi (optarg);
break;
case ‘?’:
error++;
break;
}
}
if (mtdoffset < 0) {
fprintf(stderr, "Can’t specify a negative device offset `%d’n",
mtdoffset);
exit (EXIT_FAILURE);
}
argc -= optind;
argv += optind;
/*
* There must be at least the MTD device node positional
* argument remaining and, optionally, the input file.
*/
if (argc < 1 || argc > 2 || error)
display_help ();
mtd_device = argv[0];
/*
* Standard input may be specified either explictly as "-" or
* implicity by simply omitting the second of the two
* positional arguments.
*/
img = ((argc == 2) ? argv[1] : standard_input);
}
int main(int argc, char * const argv[])
{
…
process_options(argc, argv);
…
}
其中,上面那个uboot命令,我是照葫芦画瓢,自己添加的。
【注意】
在添加uboot参数支持的时候,无意间,犯了个错误,把
static const char *short_options = "ab:fjmnopqs:uy";
写成了
static const char *short_options = "ab:fjmnopqsu:y";
把u字符放在了s和冒号中间,导致
case ‘s’:
mtdoffset = strtol (optarg, NULL, 0);
break;
中去调用strtol,出现Segmentation fault,查到最后,发现是上面u字母防错位置导致传入给strol的optarg是NULL,所以才出现Segmentation fault。
因此,要注意的就是,在添加参数支持的时候,当某个选项是需要参数的时候,比如
static const char *short_options = "ab:fjmnopqs:uy";
。。。
{"start", required_argument, 0, ‘s’},
。。。
case ‘s’:
mtdoffset = strtol (optarg, NULL, 0);
break;
上面 static const char *short_options = "ab:fjmnopqs:uy";
中的冒号“:”表示是参数的意思,s和冒号之间不能分开了,否则就误以为后面的选项是s的参数了。
【引用】
1.getopt()与getopt_long()
http://edu.codepub.com/2009/0617/6513.php
2.linux 中解析命令行参数(getopt_long用法)
http://doc.chinaunix.net/linux/201003/456376.shtml
3.getopt与optarg
http://hi.baidu.com/snailzzz/blog/item/b0c95ee95ce2a435b90e2da3.html
转载请注明:在路上 » 【整理】getopt()或getopt_long()与optarg