比如我在文件1里定义int c = 0x31323334;
在文件2里声明extern char c; 编译器并不会报错的。
//File: 1.c
char a[100] = {0x31, 0x32, 0x33, 0x34, 0x35};
char *b = "abcde";
int c = 0x31323334;
char* f(void)
{
return b;
}
//File: 2.c
#include <stdio.h>
extern char *a;
extern char b[ ];
extern char c;
extern f();
int main(void)
{
//char *d1 = (char *)(b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24));
char *d = (char *)((unsigned char)b[0] + ((unsigned char)b[1] << 8) + \
((unsigned char)b[2] << 16) + ((unsigned char)b[3] << 24));
printf("%x\n", a);
//printf("%c\n", *a);//这里运行会出错:Segmentation fault (core dumped)
printf("%x\n", f()); //"abcde"这个字串的首地址,
printf("%x\n", d); // d = f();
//printf("%x\n", d1);
//必须先将char转换成unsigned char,因为char参加运算时会被提升为int型,而对于有符号型数据,
//在扩展时,高位由符号位决定,为1则补1,为0则补0.无符号型数据全补0
printf("%x %x %x %x\n", b[0], b[1], b[2], b[3]);
printf("%x %x %x %x\n", (unsigned char)b[0], (unsigned char)b[1], \
(unsigned char)b[2], (unsigned char)b[3]);
printf("%c\n", c);
return 0;
}
运行结果:
34333231
80485d4
80485d4
ffffffd4 ffffff85 4 8
d4 85 4 8
4
虽然在文件 1 中,编译器知道 a 是一个数组,但是在文件 2 中,编译器并不知道这点。大多数编译器是按文件分别编译的,编译器只按照本文件中声明的类型来处理。所以,虽然 a 实际大小为 100 个 byte,但是在文件 2 中,编译器认为 a 是一个char*指针,只占 4 个 byte。编译器会把存在指针变量中的任何数据当作地址来处理。故文件2中a存放的数据其实是文件1中数组a的前4个元素,即文件2中a=0x34333231(小端机器),对这个未定义的地址进行访问,所以出错了。
而文件2中,编译器把b当作char数组了,在文件1中 b实际上是指向了"abcde"这个字串的首地址,故文件2中b数组的前四个元素为"abcde"这个字符串的首地址,我将文件中b数组4个元素的值转换成一个指针d,d的值与f()所返回的值相同
文件2中,编译器将c 当做char型,c的值为文件1中int c第一个字节的值