getopt是一个专门设计来减轻命令行处理负担的库函数,它可以在全局结构中记录命令参数,以便随后随时在整个程序中使用,即getopt被用来解析命令行选项参数,就不用自己写代码处理argv了。其中比较重要的函数是getopt()和getopt_long()。
(1) main()中的两个参数。声明main()函数有两种形式:int main( int argc, char *argv[] ); 和int main( int argc, char **argv );现在前者用的较多。当 C 运行时库的程序启动代码调用 main() 时,已经对命令行进行了处理。argc 参数包含参数的计数值,而 argv 包含指向这些参数的指针数组。 对于 C 运行时库,arguments 是程序的名称,程序名后的任何内容都应该使用空格加以分隔。
例如,如果使用参数 -v version www.google.com 运行一个名为 program 程序,您的 argc 将设置为 4,argv 的设置情况则是:
argv[0] - program
argv[1] - -v
argv[2] - version
argv[3] - www.google.com
(2) getopt()。getopt()原型是int getopt( int argc, char *const argv[], const char *optstring ); 调用一次,返回一个选项。 在命令行选项参数再也检查不到optstring中包含的选项时,返回-1,同时optind储存第一个不包含选项的命令行参数。
getopt() 所设置的全局变量包括:
optarg——指向当前选项参数(如果有)的指针(optarg不需要定义,在getopt.h中已经有定义)。
optind——再次调用 getopt() 时的下一个 argv 指针的索引。
optopt——最后一个已知选项。可以重复调用 getopt(),直到其返回 -1 为止.
getopt_long()的说明。getopt_long的原型是:
int getopt_long(int argc, char * const argv[], const char *optstring, const struct option *longopts, int *longindex);
这里参数longopts,其实是一个结构的实例:
struct option { const char *name; //name表示的是长参数名 int has_arg; // has_arg有3个值,no_argument(或者是0),表示该参数后面不跟参数值 // required_argument(或者是1),表示该参数后面一定要跟个参数值 // optional_argument(或者是2),表示该参数后面可以跟,也可以不跟参数值 int *flag; // 用来决定,getopt_long()的返回值到底是什么。如果 flag 成员未设置为 NULL,在处理期间遇到此选项时,会使用 val 成员的值填充它所指向的 int 值。如果 flag 成员为 NULL,在 getopt_long() 遇到此选项时,将返回 val 中的值; int val; //和flag联合决定返回值 } 代码实现实例:
/************************************************************************* > File Name: shortpara.c > Author:xiao5 > Mail: [email protected] > Created Time: 2016年02月01日 星期一 13时50分10秒 ************************************************************************/ #include <ctype.h> #include <stdio.h> #include <stdlib.h> /* getopt时必须包含 unistd头文件 */ #include <unistd.h> int main (int argc, char **argv) { int index; int c; /* 控制是否向STDERR打印错误。为0,则关闭打印 */ opterr = 0; /* getopt 用来解析短选项,第一二个参数基本都是相同的 */ /* 第三个选项传入能接受的参数,':'代表需要值 '::'代表值为可选*/ /* 如果传入了值,其值保存在optarg当中,当其值为必须是,若没有传入值则会报错 缺少值 */ /* getopt返回匹配的选项 例如a/b/c */ /* 未匹配值时返回? 解析完时,会返回-1 跳出 */ while ((c = getopt (argc, argv, "a:bc:d::")) != -1) { /* printf("进入判断程序\n"); */ switch (c) { case 'a': printf("检测到-a选项, 其参数为:%s\n", optarg); break; case 'b': printf("检测到-b选项\n"); break; case 'c': printf("检测到-c选项,其参数为:%s\n", optarg); break; /* 用来检测其他意外的值 */ case 'd': printf("检测到-d选项, 其参数为: %s\n", optarg); break; case '?': /* optopt为在没有匹配任何选项时,保存的选项值 */ /* 例如-n,没有与上面匹配,则此时optopt=a 或optopt=c */ if (optopt == 'a'|| optopt == 'c' || optopt == 'd') fprintf (stderr, "选项 -%c 需要一个参数.\n", optopt); else if (isprint (optopt)) fprintf (stderr, "`-%c'未定义\n", optopt); else fprintf (stderr, " `\\x%x' 未定义\n", optopt); break; default: abort();//跳出while循环 } } /* printf("Char c: %d\n", c); */ /* 最后检测命令行给的选项是否已经解析完 optind是当前解析到选项的索引 判断依据是如果解析的个数小于argc,那么就是没有解析完 */ for (index = optind; index < argc; index++) printf ("未定义的参数: %s\n", argv[index]); return 0; }
运行情况:
长参数代码实例:
/************************************************************************* > File Name: longpara.c > Author:xiao5 > Mail: [email protected] > Created Time: 2016年02月01日 星期一 13时51分16秒 ************************************************************************/ #include <stdio.h> #include <stdlib.h> /* 使用getopt_long时不需要unistd*/ #include <getopt.h> /* 用来作为一个标志的值. */ static int verbose_flag; int main (int argc, char **argv) { int c; while (1) { /* 结构说明 struct option { const char *name; //匹配的长选项名 int has_arg; //指定参数选项no_argument required_argument optional_argument 无值 值必须 值可选 int *flag; //标志位,数据类型为 int* int val; //值,标志位不为0时,如果该选项指定,那么flag=val 此时val不可作为case值 //否则val可以作为短选项 也就相当于case }; */ static struct option long_options[] = { /* 如果指定了-verbose 那么verbose_flag = 1*/ {"verbose", no_argument, &verbose_flag, 1}, /* 如果指定了-brief 那么verbose_flag = 0*/ {"brief", no_argument, &verbose_flag, 0}, /* --add = -a 不带参数*/ {"add", no_argument, 0, 'a'}, {"append", no_argument, 0, 'b'}, /* --delete=XX = -dXX 带参数*/ {"delete", required_argument, 0, 'd'}, {"create", required_argument, 0, 'c'}, {"file", required_argument, 0, 'f'}, /* 很明显5438不可能用一个ANSCI表示出来,那么这个可以直接用case就可以*/ {"a_very_long_arg", no_argument, 0, 5438}, /* 最后为空值,来标识结束 */ {0, 0, 0, 0} }; /* 因为没有了optind,那么就要用一个值来存储当前索引 */ int option_index = 0; /* 前三个参数与getopt相同,第四个为option,第五个为存索引int的指针*/ c = getopt_long (argc, argv, "abc:d:f:", long_options, &option_index); /* 当解析完返回-1 跳出循环 */ if (c == -1) break; switch (c) { case 0: /* 当 flag不为0时,遇到那些选项 getopt_long返回0*/ if (long_options[option_index].flag != 0) break; printf ("选项 %s", long_options[option_index].name); if (optarg) printf (" 值 %s", optarg); printf ("\n"); break; case 'a': puts ("选项 -a\n"); break; case 'b': puts ("选项 -b\n"); break; //长选项 case 5438: puts ("选项 --a_very_long_arg\n"); break; break; case 'c': printf ("选项 -c 值为 `%s'\n", optarg); break; case 'd': printf ("选项 -d 值为 `%s'\n", optarg); break; case 'f': printf ("选项 -f 值为 `%s'\n", optarg); break; case '?': /* getopt_long 会自动输出错误,不像getopt需要自己检测 */ break; default: abort (); } } /* 检测是否设置了标志位 */ if (verbose_flag) puts ("verbose 标志已被设置"); /* 输入未解析完的选项. */ if (optind < argc) { printf ("无效选项: "); while (optind < argc) printf ("%s ", argv[optind++]); putchar ('\n'); } exit (0); }