传递命令行参数的程序是一种标准的UNIX程序,现在各种APP满天飞,谁还弄那??? 也许是吧,不过学了这么长时间的C, 总感觉要写一些能用的程序出来,克隆克隆GNU的一些小工具吧,如果能做到的话。
getopt是一种接口,提供了一个可以让用户更简单的处理命令行参数的方法,根据Eric Raymond的话来说,是由于这个特性,是的不同的程序之间可以交互(扯远了。。。)
<getopt.h> 和 <unistd.h>中提供了一些函数,最重要的是:
int getopt(int argc, char * const argv[], const char *optstring);
int getopt_long(int argc, char * const argv[], const char *optstring,
const struct option *longopts, int *longindex);
//还有一些全局变量,诸如:
int optopt, optind, opterr;
char *optarg;
<getopt.h>中还有一个函数, getopt_long_only, 不过我觉的暂时用不到。
getopt_long 是 getopt 的超集,同时它还能处理长参数,我不会说的详细的像GNU DOC一样,说一下它有用的地方;
1. optstring语句:
它就是一个字符串,包含所有的短参数,eg: ":abc:d::"
第一个字符表示表示如何处理缺少optarg的情况,这样可以和unrecognized option情况区分(见下文);
单个字母表示就是参数啦, 如果一个字母后面有一个冒号(colon),那么该参数必须有一个子参数,如果有俩,说明子参数是 可选的;
如果字母W后有一个分号(semicolon),还必须是W,就把 -W foo 看成 long option,这个几乎用不到,我们有getopt_long了。
2. struct option
struct option {
const char *name;
int has_arg;
int *flag;
int val;
}
第一个 name是名字;
第二个 has_arg是个标志, 有no_argument, required_argument, optional_argument 三种;
第三个 flag 说明如何处理参数,这是个指针。。。 如果指向NULL说明返回val的值, 如果长参数和短参数意义相同,那就简单了;
如果不是NULL,那么getopt_long返回0, flag指向了一个和val相同的地址,否则不变。
返回0的时候可以通过longindex来定位,它会指向我们遇到的了哪个参数; 这样就方便我们那些只有长参数的参数了。。。
eg:
static struct option long_options[] = {
{"add", required_argument, 0, 0 },
{"append", no_argument, 0, 0 },
{"delete", required_argument, 0, 0 },
{"verbose", no_argument, 0, 0 },
{"create", required_argument, 0, 'c'},
{"file", required_argument, 0, 0 },
{0, 0, 0, 0 }
};
3.我们用这两个函数的时候都是用switch语句,
while ((c = getopt(argc, argv, optstring)) != -1) {
switch(c) {
case 'a': //....
}
}
//或者
while (1) {
c = getopt_long(argc, argv, optstring, longopts, &longindex);
if (c == -1)
break;
switch (c) {
case ' ': //...
}
}
来工作的,返回的是我们遇到的参数, 遇到第一个非参数时返回-1; 这样我们跳出循环, 当然还有其他情况, 总结一下所有情况:
1:遇到 不是以 ‘-' 和 ‘--’ 开始的argv[i]表示遍历完参数了;
2:遇到 单个参数 '--' 说明参数终止,以后的都是非参数变量;
3:遇到不认识的参数 返回 '?' 遇到参数少子参数默认也返回'?', 不过我们可以更改optstring的第一个字符;
返回'?'后,将有问题的参数 给 optopt,把错误信息给opterr;
4.遍历完所有参数:
接下来optind会指向第一个非参数变量,知道 optind == argc 这样 argv[optind] = ‘\0';
总的来说 getopt还是很好用的,在 gnu的实现里面,使用getopt_long一个函数实现了getopt和getopt_long_only两者,这是后话了,我们使用的时候就是设置一些标志位,然后根据参数跳到某个函数去,顺便吐槽下GNU的库函数的实现,实在是太难懂了。。。
这是我写的第一篇博客,从基本的东西做起,把自己的学习记录下来,就像日记一样。