默认的getopt、getopt_long是不可重入的,也就是说,假设你使用它开发交互式应用程序,循环获取用户命令,它只能正确解析第一次命令行输入。
你可以先看这个问题
还有一个以前的帖子
这个帖子给的解决方案发现并不能解决问题。
于是我决定把libc的源文件自己下载下来,编译链接到自己的程序里,另我惊喜的是,glibc-2.7,已经实现了它的可重入版本,于是我想直接使用这个可重入版本的函数_getopt_long_r。
它的posix目录下有getopt.h getopt_int.h getopt.c getopt1.c
拷到你自己的项目文件夹下使用
使用时添加上
#include "getopt.h"
#include "getopt_int.h"
但是当我使用_getopt_long_r时,编译器老报,这个函数没有定义的错误(undefined),也就是说,我的库里面没有包含这个函数,其实我的/usr/include下根本没有getopt_int.h这个头文件。
于是我决定测试一下这个getopt.c和getopt1.c
gcc -c getopt.c
objdump -t getopt.c
结果发现
getopt.o: file format elf32-i386
SYMBOL TABLE:
00000000 l df *ABS* 00000000 getopt.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .note.GNU-stack 00000000 .note.GNU-stack
00000000 l d .comment 00000000 .comment
说明编译出来的文件一个符号都没有,这样链接还是链接到c库,而c库里没有包含的函数,比如_getopt_long_r肯定是找不到了。
而假设你自己写个文件
//test.c
#include <stdio.h>
void fun(){}
int main(int argc, char *argv[]) { printf("test\n"); }
|
gcc -c test.c
objdump -t test.o
test.o: file format elf32-i386
SYMBOL TABLE:
00000000 l df *ABS* 00000000 test.c
00000000 l d .text 00000000 .text
00000000 l d .data 00000000 .data
00000000 l d .bss 00000000 .bss
00000000 l d .rodata 00000000 .rodata
00000000 l d .note.GNU-stack 00000000 .note.GNU-stack
00000000 l d .comment 00000000 .comment
00000000 g F .text 00000005 fun
00000005 g F .text 00000026 main
00000000 *UND* 00000000 puts
说明了一个问题,那就是getopt中的函数并没有真正进行编译。
要不然它应该会有类似下面的结果,符号表里应该包括fun,即函数名
在getopt.c如下位置添加#define _LIBC 和#define _(x) (x)
35:#include <stdio.h> 36:#define _LIBC 37:#define _(x) (x)
|
同理在getopt1.c中修改为
33:#include <stdio.h> 34:#define _LIBC
|
代码实例:
//test.c 和getopt.c getopt1.c getopt.h getopt_int.h在同一目录下
#include <stdio.h> #include "getopt.h" #include "getopt_int.h" static char *common_options = "?V"; static struct option common_long_options[] = { {"version", 0, NULL, 'V'}, {"help", 0, NULL, '?'}, {0, 0, 0, 0} };
int main(int argc, char *argv[]) { char opt; int option_index = 0; struct _getopt_data local_opt_data = _GETOPT_DATA_INITIALIZER; while(-1 != (opt = _getopt_long_r(argc, argv, common_options, common_long_options, &option_index, &local_opt_data))){ switch(opt){ case 0: if(!strcmp(common_long_options[option_index].name, "process")) ; else printf("the param for display is not right\n"); case 'V': printf("\tmysnort 0.0.1\n"); break; case ':': printf("option needs a value\n"); break; default://'?'
fprintf(stderr, "\t%serror usage, type help\n",argv[0]); } } if(local_opt_data.optind < argc) { printf("non-option argv-elements: "); while (local_opt_data.optind < argc) printf("%s ,try \"help\"", argv[local_opt_data.optind++]); printf("\n"); } return 0; }
|
编译gcc test.c getopt.c getopt1.c
./a.out
运行结果
root@xsf-pc:/my/study/project# ./a.out -V
mysnort 0.0.1
此时,_getopt_long_r已经成功调用了,要使用这个做交互式应用程序,还需要自己定义函数实现argc,argv的重写,当然你也可以定义二维数组,将输入的参数字符串读入到二维数组中,然后将这个数组和数组包含的字符串数传入_getopt_long_r,二维数组必须以null结尾,而字符串数不包括null,具体怎么做,读者自己写写程序试试,在此就不剥夺读者自己写程序的权利了。由于_getopt_long_r是可重入的,你将正确解析的命令行字符串输入传入这个分析函数,就能进行连续分析了。这样linux的交互式程序设计就实现了。就像gdb似的。
你解析的参数应如下所示。
int n = 2;
char *argv[24] = {"help" , "-V", NULL};
<script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/buttonLite.js#style=-1&uuid=&pophcol=3&lang=zh"></script> <script type=text/javascript charset=utf-8 src="http://static.bshare.cn/b/bshareC0.js"></script>
阅读(536) | 评论(0) | 转发(0) |