《C陷阱与缺陷》提到要特别注意extern char *a与extern char a[]之间的区别。所以特意测试了一下。测试环境VC6
b.cpp
char *a="ABCDEF";
char b[]="ABCDEF";
第一种情况:主文件中声明
extern char a[];
extern char b[];
#include <iostream.h>
extern char a[];
extern char b[];
int main()
{
cout<<a<<endl;
cout<<b<<endl;
return 0;
}
此时运行结果:
可以看到a乱码了。
第二种情况:主文件声明
extern char *a;
extern char *b;
#include <iostream.h>
extern char *a;
extern char *b;
int main()
{
cout<<a<<endl;
cout<<b<<endl;
return 0;
}
此时运行结果:
可以看到a正确输出,然后程序出错。
原因分析:
char *a="ABCDEF";
char b[]="ABCDEF";
定义a时,a存储的字符串常量的地址。当以extern char a[];声明外边变量a时,编译器在b.cpp文件中寻找到变量a,并
认为a是char数组类型。a中本来存储的"ABCDEF"的地址,现在编译器却把a当作char数组,所以把a中存储的地址翻译
成字符,如果没有对应的字符,应该就乱码了。
定义b时,b是作为字符串数组的首址。当以extern char *b;声明外部变量b时,编译器在b.cpp中寻找到变量b,并认为b是char*类型。所以把"ABCD"当作地址,并访问这个地址,所以出现内存访问出错。
验证:
b.cpp
char *a="ABCDEF";
char b[]="ABCDEF";
//获取指针a本身存储的内容,并转化为无符号整数
unsigned int a_address()
{
return (unsigned int)a;
}
//32为系统,所以获取数组前四个字节转化为无符号整数
unsigned int b_int()
{
return *(unsigned int*)b;
}
test.cpp
#include <iostream.h>
extern char a[];
extern char *b;
extern unsigned int a_address();
extern unsigned int b_int();
int main()
{
if(*(unsigned int*)a==a_address())
cout<<"指针a被错误的认为是数组"<<endl;
if((unsigned int)b==b_int())
cout<<"数组b被错误的认为是指针"<<endl;
return 0;
}
所以,声明和定义一定要以相同的形式出现。