getoptgetopt_long函数的使用教程
今天准备在阅读Android系统dumpsys源码的时候,初次看到getopt_long函数,看着有点懵逼,严重阻塞我的源码阅读,因此下定决心要研究明白它,顺便记录一下如何使用,防止遗忘。
getopt函数的使用
getopt函数主要是用于方便我们解析命令行参数的C函数, 允许你处理短选项(以单个短划线开头的选项,例如-a,-b)和带参数的短选项(例如-o filename)。比较常用的场景是,我们自己开发了一个小工具,在解析命令行参数的时候,非常方便。
int getopt(int argc, char * const argv[],const char *optstring);
参数
argc、argv[]
argc和argv就是main函数的参数是一致的,直接传入即可
optstring
char *optstring = "ab:";
optstring的使用比较简单。短选项字符串:a表示-a选项,不带参数。b:表示-b选项,带一个参数。注意不支持带多个参数哈
返回值
- 如果找到了合法的选项字符,比如 -a 或 -b,则 getopt 返回这个字符,例如 ‘a’ 或 ‘b’。
- 如果选项字符后面有冒号(:),表示这个选项需要一个参数。例如,如果 shortopts 是 b:, 选项 -b 必须有一个参数。在这种情况下,getopt 会把参数的指针存储在全局变量 optarg 中。
- 如果发现一个选项字符不在 shortopts 中,返回 ‘?’ 并且 opterr 设置为 1(默认)。
- 如果选项要求参数而没有提供参数(例如 -b 后没有参数,shortopts 中为 b:),同样返回 ‘?’,并且 opterr 设置为 1(默认)。同时 optopt 会保存无法识别的选项字符。
- 识别到选项结束,当所有选项都解析完成时,getopt 返回 -1,并且全局变量 optind 设置为第一个非选项参数的索引。
全局变量
- optarg:指向当前选项的参数值(如果存在)。
- optind:指向下一个要处理的命令行参数的索引。
- optopt:存储当前未被识别的选项字符。
- opterr:如果为非零,getopt 会输出错误信息到 stderr(默认是 1)。
Demo:getopt
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[]) {
int opt;
printf("beging optind = %d\n", optind);
opterr = 0;
printf("--------------------------------------------------------------\n");
while ((opt = getopt(argc, argv, "ab:c:")) != -1) {
printf("opt = %c, optind = %d, optarg = %s, opterr = %d, optopt = %c\n", opt, optind, optarg, opterr, optopt);
switch (opt) {
case 'a':
printf("Option -a\n");
break;
case 'b':
printf("Option -b with argument '%s'\n\n", optarg);
break;
case 'c':
printf("Option -c,with argument '%s'\n\n", optarg);
break;
case '?':
fprintf(stderr, "Option -%c requires an argument.\n\n", optopt);
return 1;
default:
fprintf(stderr, "Usage: %s [-a] [-b value] [-c]\n\n", argv[0]);
exit(EXIT_FAILURE);
}
printf("--------------------------------------------------------------\n");
}
int index = optind;
for (index; index < argc; index++) {
printf("Non-option argument: %s\n", argv[index]);
}
return 0;
}
Demo验证结果如下:
-
正常情况下:
-
需要参数,但不传入情况:
-
非参数选项
getopt_long
getopt_long和getopt不同的地方在于,getopt_long可以同时接受短选项和长选项,并可以选择不接受短选项
int getopt_long(int argc, char * const argv[],
const char *optstring,
const struct option *longopts, int *longindex);
参数
argc和argv
argc和argv就是main函数的参数是一致的,直接传入即可
optstring
optstring用户和getopt的用法一致,如果选择不接受短参数,可以填NULL
longopts
getopt_long和getopt最大的差别就在于这里,这个参数需要传入一个结构体数组。结构体长这个样子。
struct option
{
const char *name; //长选项的名字
int has_arg;//长选项是否带参数
int *flag;//标志变量。如果为 NULL,则 getopt_long 返回 val 的值。如果非 NULL,则 getopt_long 设置此指针指向变量为 val,并返回 0
int val;
};
longindex
如果不为 NULL,它指向一个整数,该整数保存匹配的长选项在 longopts 数组中的索引。
全局变量
同getopt
Demo:getopt_long
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
int flag = 0;
struct option long_options[] = {
{"help", required_argument, &flag, 1024},
{"best", required_argument, NULL, 2048},
{"only", required_argument, NULL, 'o'},
{0, 0, 0, 0}
};
int main(int argc, char *argv[]) {
int opt;
int option_index = 0;
printf("--------------------------------------------------------------\n");
while ((opt = getopt_long(argc, argv, "o:", long_options, &option_index)) != -1) {
printf("opt = %d, %c, flag = %d, option_index = %d\n\n", opt, opt, flag, option_index);
switch (opt) {
case 0:
printf("flag = %d\n", flag);
printf("flag is not null, value: %s\n\n", optarg);
break;
case 2048:
printf("best called, value: %s\n\n", optarg);
break;
case 'o':
printf("-o or --only called , value: %s\n\n", optarg);
break;
case '?':
printf("Usage: xxxxxx \n\n");
exit(EXIT_FAILURE);
default:
printf("?? getopt returned character code 0%o ??\n\n", opt);
}
printf("--------------------------------------------------------------\n");
}
int i = optind;
for (i; i < argc; i++) {
printf("Remaining argument: %s ??\n", argv[i]);
}
return 0;
}
Demo验证结果: