|
发帖者:alert7 讨论区:Unix Hacking推荐区 标题:[tips] extern与指针的指针变量 发信站:安全焦点(2003年9月8日13时02分48秒) extern与指针的指针变量
by alert7
gcc的一点小经验,可能您已经知道,比较肤浅,但是不知道的可能会郁闷好几个小时。
一直以来,我们都认为char *argv[]与char **argv是等价的。而且这样 也一直没有出错。所以侥幸的认为char *argv[]与char **argv是等价的,原型 不一样,但至少是通用的。 但是,昨天的一个BUG调试了一天,郁闷绝望之余结果发现是定义指针的指针变量 惹的祸,按照原型,应该定义成指针数组。问题解决,现把经验写成本文,以使来者少 走一些弯路。
以下的例子是我抽象出来的,table被定义成指针数组,在实际现实中o.c可能是第三 方提供的软件,没有源代码,你可能草草的把table定义为extern void ** ;
[root@redhat73 root]# cat o.c #include <stdio.h> void * table[]={"0","1","2","3",NULL};
int test(void ) {
return 0; }
[root@redhat73 root]# cat t.c #include <stdio.h> int main(int argc, char *argv[]) { extern void **table; int t;
printf("table %x\n",&table); printf("&table[1] %x\n",&table[1]); printf("table[1] %s\n",table[1]);
return 0; } [root@redhat73 root]# gcc -c t.c [root@redhat73 root]# gcc -o t t.o o.o [root@redhat73 root]# ./t table 8049518 &table[1] 8048507 <-----这里显然不是我们想要的 table[1] (null) <-----这里更是出错了
我们来看下汇编代码 08048400 <main>: 8048400: 55 push %ebp 8048401: 89 e5 mov %esp,%ebp 8048403: 83 ec 08 sub $0x8,%esp 8048406: 83 ec 08 sub $0x8,%esp 8048409: 68 18 95 04 08 push $0x8049518 <------table地址 804840e: 68 d8 84 04 08 push $0x80484d8 8048413: e8 d8 fe ff ff call 80482f0 <_init+0x58> 8048418: 83 c4 10 add $0x10,%esp 804841b: 83 ec 08 sub $0x8,%esp 804841e: a1 18 95 04 08 mov 0x8049518,%eax <-----把0x8049518地址中的值放到eax中 8048423: 83 c0 04 add $0x4,%eax <-----再把这个值加4,这显然与我们的本意有出入 8048426: 50 push %eax 8048427: 68 e2 84 04 08 push $0x80484e2 804842c: e8 bf fe ff ff call 80482f0 <_init+0x58> 8048431: 83 c4 10 add $0x10,%esp 8048434: 83 ec 08 sub $0x8,%esp 8048437: a1 18 95 04 08 mov 0x8049518,%eax 804843c: 83 c0 04 add $0x4,%eax 804843f: ff 30 pushl (%eax) 8048441: 68 f0 84 04 08 push $0x80484f0 8048446: e8 a5 fe ff ff call 80482f0 <_init+0x58> 804844b: 83 c4 10 add $0x10,%esp 804844e: b8 00 00 00 00 mov $0x0,%eax 8048453: c9 leave 8048454: c3 ret
再来看下按照原型定义的extern void *table[]; #include <stdio.h> int main(int argc, char *argv[]) { extern void *table[]; int t;
printf("table %x\n",&table); printf("&table[1] %x\n",&table[1]); printf("table[1] %s\n",table[1]);
return 0; } [root@redhat73 root]# gcc -c t.c [root@redhat73 root]# gcc -o t t.o o.o [root@redhat73 root]# ./t table 8049508 &table[1] 804950c table[1] 1 08048400 <main>: 8048400: 55 push %ebp 8048401: 89 e5 mov %esp,%ebp 8048403: 83 ec 08 sub $0x8,%esp 8048406: 83 ec 08 sub $0x8,%esp 8048409: 68 08 95 04 08 push $0x8049508 804840e: 68 c8 84 04 08 push $0x80484c8 8048413: e8 d8 fe ff ff call 80482f0 <_init+0x58> 8048418: 83 c4 10 add $0x10,%esp 804841b: 83 ec 08 sub $0x8,%esp 804841e: 68 0c 95 04 08 push $0x804950c <--------这里就对了 8048423: 68 d2 84 04 08 push $0x80484d2 8048428: e8 c3 fe ff ff call 80482f0 <_init+0x58> 804842d: 83 c4 10 add $0x10,%esp 8048430: 83 ec 08 sub $0x8,%esp 8048433: ff 35 0c 95 04 08 pushl 0x804950c 8048439: 68 e0 84 04 08 push $0x80484e0 804843e: e8 ad fe ff ff call 80482f0 <_init+0x58> 8048443: 83 c4 10 add $0x10,%esp 8048446: b8 00 00 00 00 mov $0x0,%eax 804844b: c9 leave 804844c: c3 ret
所以,我们还是要严格按照函数的原型来定义。
经过一些实验,指针的指针变量经过extern的申明就需要注意了, 这时候指针的指针变量和指针数组就不能通用了。
|