Chinaunix首页 | 论坛 | 博客
  • 博客访问: 320257
  • 博文数量: 43
  • 博客积分: 1044
  • 博客等级: 准尉
  • 技术积分: 658
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-20 14:56
个人简介

人法地,地法天,天法道,道法自然。

文章分类

全部博文(43)

文章存档

2019年(1)

2013年(3)

2012年(15)

2011年(24)

分类: C/C++

2012-04-13 12:06:04

多文件C程序中,有使用extern来导入其他文件的符号。在两个文件中extern的符号类型不一,会有什么后果。看以下例子:

文件t1.c:
  1. int a[16] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
  2. int *p = a;

  3. int show()
  4. {
  5.     printf("a = %p p = %p &p = %p \n",a,p,&p);
  6.     return 0;
  7. }
文件t2.c:
  1. #include <stdio.h>

  2. extern int *a;
  3. extern int p[];

  4. int main()
  5. {
  6.     int x = 0;
  7.     int y = 0;

  8.     show();
  9.     printf("a = %p p = %p &a = %p &p = %p p[0] = 0x%x\n",a,p,&a,&p,p[0]);
  10.     x = a[3];
  11.     y = p[3];

  12.     printf("x = %d y = %d \n",x,y);
  13.     return 0;
  14. }
可以看到t1.c和t2.c中的符号a和p的类型是不一样的。再编译和运行
  1. $gcc -g -Wall *.c
  2. $./a.out
  3. a = 0x8049760 p = 0x8049760 &p = 0x80497a0
  4. a = (nil) p = 0x80497a0 &a = 0x8049760 &p = 0x80497a0 p[0] = 0x8049760
  5. Segmentation fault (core dumped)
在运行期core dump了。可以看到在t2.c中导入的符号与t1.c中的符号好想不一致哦。
而且看出main.a是NULL,就找到了core dump的原因(t2.c:13)。
经过分析可以看出show.a,show.p,main.&a,main.p[0]是一样的,show.&p,main.&p是一样的。
再进一步分析:
show.a和show.p一致是因为在t1.c中a为数组,也就是所谓的常量指针。然后用a给p赋值,
所以,show.a和show.p一致。
那么为什么show.a和main.&a是一样的呢?
如果&a理解为是t1.c的a的地址,那么就很好理解main中的a为什么是NULL了。show.a的第一个元素
的值为0。那么作为指针的main.a的值为0,所以,就变成0了。
试试这样的代码:
  1. int **p = (int *)a;
  2. printf("p = %p \n",*p);
其实,show.a就相当于a,main.a就相当于*p。

所以,show.a和main.a的地址是同一个,show.p和main.p的地址也是一样的。所以,在一个文件中导入其他文件的符号,其实符号的地址是一样的。不用管是什么类型。

在t1.c中a为数组,在t2.c中a为指针。那么两个a的地址是一样的。对指针a的值就是数组a的第一个值,而数组a的值为0。所以,在32位系统上指针a的值就变成NULL了。
所以,在t1.c中的p是指针,在t2.c中p是数组。应用上一个结论,指针p的地址与数组p的地址是一个。那么y的值就是p地址后的第四个整数。

最终的结论就是,导入符号的时候,导入的符号与原符号地址相同。
那么,以下代码的结果是什么?
  1. a = &a;
  2. for(int i = 0; i < 16; i++){
  3.     printf("0x%x ",a[i]);
  4. }
  5. printf("\n");
请先不要编译运行,先想想结果是什么,然后在运行去验证。
阅读(2936) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~