c extern 问题
在一个源文件中定义 int a[5]={1,2,3,4,5}; int *b=a;
在另外一个文件中写一下代码 extern int *a; extern int b[];
printf("%d",a);
打印出的值不是一个地址 ,而是a[0]的值
一般我们使用extern的时候像下面这样肯定就没问题
int a
extern int a
现在是
int a[]
extern int *a
会不会编译器就理解为你引用的是int *a[]这个玩意,所以就会导致现在的结果
求大侠解释
在另外一个文件中写一下代码 extern int *a; extern int b[];
printf("%d",a);
打印出的值不是一个地址 ,而是a[0]的值
一般我们使用extern的时候像下面这样肯定就没问题
int a
extern int a
现在是
int a[]
extern int *a
会不会编译器就理解为你引用的是int *a[]这个玩意,所以就会导致现在的结果
求大侠解释
对于所有的非局部变量, 如全局变量, 都需要链接的时候重定位,原因很简单, 在c 语言转换成代码的时候, 对于这个全局变量不知道要去访问那个地址,一个简单的例子如下
int abcd[10];
int main()
{
int a =0;
a = abcd[0];
}
对于这样的c 代码, 里面a = abcd[0] 要访问全局变量,就是内存中的一个地方,在编译成d.o的时候, 无法得知abcd 的地址, 因为这时候不知道其他文件中还有多少全局变量,函数,一下是编译出来的d.o 的反汇编代码
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 10 sub $0x10,%esp
6: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
d: a1 00 00 00 00 mov 0x0,%eax
e: R_386_32 abcd
12: 89 45 fc mov %eax,-0x4(%ebp)
15: c9 leave
16: c3 ret
在d 行, 访问了内存地址为0 的地方, 还有一个标记, 这里是类型为 R_386_32的重定位,在链接之后, 确定了有多少全局变量以后会把这里的地址修正过来,
08048394 <main>:
8048394: 55 push %ebp
8048395: 89 e5 mov %esp,%ebp
8048397: 83 ec 10 sub $0x10,%esp
804839a: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
80483a1: a1 40 96 04 08 mov 0x8049640,%eax
80483a6: 89 45 fc mov %eax,-0x4(%ebp)
80483a9: c9 leave
80483aa: c3 ret
80483ab: 90 nop
看上面的8048a31 和前面对比 所有代码都一样,就是这里不一样, 他在访问8049640 这个内存地址,可以猜想 这里就是abcd 数组的地址, 可以验证一样, 用readelf 可以查看一个执行文件的符号表
这里只是一种一部分
58: 0804960c 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
59: 08049668 0 NOTYPE GLOBAL DEFAULT ABS _end
60: 08049640 40 OBJECT GLOBAL DEFAULT 25 abcd
61: 0804960c 0 NOTYPE GLOBAL DEFAULT ABS _edata
62: 08048415 0 FUNC GLOBAL HIDDEN 13 __i686.get_pc_thunk.bx
63: 08048394 23 FUNC GLOBAL DEFAULT 13 main
看 abcd 的地址就是8049640, 在上面讲了这么多,
在一个文件里面声明一个数组,另外一个文件声明指针, 在链接的时候 会为数组安排地址,
但是
extern int *a
printf("%d",a);
这样的代码 因为a 是一个变量, 需要a 的值, 就留下一个重定位
00000000 <main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp
6: 83 ec 10 sub $0x10,%esp
9: a1 00 00 00 00 mov 0x0,%eax
a: R_386_32 a
在链接完之后会把a 的地址让这里放, 所以就会读到a 数组的第一个元素,
正确的写法应该是extern int a[];
因为声明的是一个数组
00000000 <main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp
6: 83 ec 10 sub $0x10,%esp
9: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp)
10: 00
d: R_386_32 a
a 的含义是数组的地址, 你需要的也是a 的地址, 所以这里第9 行的 汇编代码也是需要重定位的, 不同的是前面有个美元符号
就是立即数的意思, 不是访问内存, 在重定位之后 直接把这个地址传给printf 了,
这就是2个的不同点,
c 语言的一句话, 类型决定operation
int abcd[10];
int main()
{
int a =0;
a = abcd[0];
}
对于这样的c 代码, 里面a = abcd[0] 要访问全局变量,就是内存中的一个地方,在编译成d.o的时候, 无法得知abcd 的地址, 因为这时候不知道其他文件中还有多少全局变量,函数,一下是编译出来的d.o 的反汇编代码
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 10 sub $0x10,%esp
6: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
d: a1 00 00 00 00 mov 0x0,%eax
e: R_386_32 abcd
12: 89 45 fc mov %eax,-0x4(%ebp)
15: c9 leave
16: c3 ret
在d 行, 访问了内存地址为0 的地方, 还有一个标记, 这里是类型为 R_386_32的重定位,在链接之后, 确定了有多少全局变量以后会把这里的地址修正过来,
08048394 <main>:
8048394: 55 push %ebp
8048395: 89 e5 mov %esp,%ebp
8048397: 83 ec 10 sub $0x10,%esp
804839a: c7 45 fc 00 00 00 00 movl $0x0,-0x4(%ebp)
80483a1: a1 40 96 04 08 mov 0x8049640,%eax
80483a6: 89 45 fc mov %eax,-0x4(%ebp)
80483a9: c9 leave
80483aa: c3 ret
80483ab: 90 nop
看上面的8048a31 和前面对比 所有代码都一样,就是这里不一样, 他在访问8049640 这个内存地址,可以猜想 这里就是abcd 数组的地址, 可以验证一样, 用readelf 可以查看一个执行文件的符号表
这里只是一种一部分
58: 0804960c 0 NOTYPE GLOBAL DEFAULT ABS __bss_start
59: 08049668 0 NOTYPE GLOBAL DEFAULT ABS _end
60: 08049640 40 OBJECT GLOBAL DEFAULT 25 abcd
61: 0804960c 0 NOTYPE GLOBAL DEFAULT ABS _edata
62: 08048415 0 FUNC GLOBAL HIDDEN 13 __i686.get_pc_thunk.bx
63: 08048394 23 FUNC GLOBAL DEFAULT 13 main
看 abcd 的地址就是8049640, 在上面讲了这么多,
在一个文件里面声明一个数组,另外一个文件声明指针, 在链接的时候 会为数组安排地址,
但是
extern int *a
printf("%d",a);
这样的代码 因为a 是一个变量, 需要a 的值, 就留下一个重定位
00000000 <main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp
6: 83 ec 10 sub $0x10,%esp
9: a1 00 00 00 00 mov 0x0,%eax
a: R_386_32 a
在链接完之后会把a 的地址让这里放, 所以就会读到a 数组的第一个元素,
正确的写法应该是extern int a[];
因为声明的是一个数组
00000000 <main>:
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 e4 f0 and $0xfffffff0,%esp
6: 83 ec 10 sub $0x10,%esp
9: c7 44 24 04 00 00 00 movl $0x0,0x4(%esp)
10: 00
d: R_386_32 a
a 的含义是数组的地址, 你需要的也是a 的地址, 所以这里第9 行的 汇编代码也是需要重定位的, 不同的是前面有个美元符号
就是立即数的意思, 不是访问内存, 在重定位之后 直接把这个地址传给printf 了,
这就是2个的不同点,
c 语言的一句话, 类型决定operation
a[] = a [0] = a ,应该就是这样了,注意是地址哈
posted on 2010-12-16 18:36 MorningChen 阅读(281) 评论(0) 编辑 收藏 举报