首页 > 技术文章 > 理解extern char s[100]与extern char *s

johnnyflute 2014-03-11 14:49 原文

在x.c中定义了一个字符数组 char s[100],
在l.c中进行引用extern char s[200], 有些c程序新手经常把它写成extern char *s。 这两种写法的含义一样吗?

首先得理解声明与定义的含义:
定义一个变量意味着要给它进行内存分配, 而声明一个变量则可以在其他文件中, 只是进行一种声明, 表示有这个变量存在, 但是在其他文件中定义, 声明后不用分配内存。

我们看一下extern char s[100]与extern char *s在执行s[10]的取值过程是什么样的:

1、 extern char s[100], s是个符号, 它既是一个数组的名称, 又是数组的起始地址(作为名称是因为他是一个标号,作为地址是因为symbol代表的就是一个地址), 假设编译器在编译的时候给s分配的地址是6789, 那么程序在执行s[10]的时候, 先找到s符号的地址6789, 然后在取(6789+10)地址上的内容。

2、extern char *s它声明了s是个指针, 既然是指针, 那么取址的过程就是间接的。 s这个符号在编译的时候也是有地址的, 不过这个地址上的内容又是一个地址, 在这个地址上保存的才是要存取的内容。当在x.c中定义s为字符数组后, 在l.c中声明s却是个指针, 这样在用s[10]操纵的时候会出现什么问题呢? 
s在x.c中被编译器分配的地址是6789, 在l.c中被当成指针了, 所以先找到6789这个地址, 在这个地址上取值作为内容的地址,6789上实际保存的是s[0]的值, 我们假设为'a', 然后程序会把'a'这个值当成地址, 然后去'a'这个地址上取内存内容, 'a'地址上显然存放的是内核数据段或代码段, 应用程序显然会报错的。 如果s[0]存放的即使是应用层程序可以访问的内容, 那么程序也会出现莫名其妙的bug。 

所以c程序员一定要搞清数组和指针并不是完全相同的。

 

上面这段其实是在网上摘的,还有一点要说讲清楚:对于需要重定向的”标号“,在链接前,标号代表的地址都是零,以上面的文字中l.c为例,由于他不知道也不需要知道要链接的另一个文件是char []型的,所以对s的操作是按照指针来操作,将数组当作指针来操作当然会出错。

推荐阅读