假顶有一个C程序,它由两个源文件组成
//demo1.c
extern int n;
//demo2.c
long n;
这里假定两个语句都不在任何一个函数体内,因此n是外部变量。
这是一个无效的C程序,因为同一个外部变量名在两个不同的文件中被声明为不同的类型。然而,大多数C语言的实现却不能检测出这种错误。
当这个程序运行时,究竟会发生什么情况呢?存在很多的可能情况。
- C语言编译器足够“聪明”,能够检测到这一一类型的冲突。 编程人员将会得到一条诊断消息, 报告变量n在两个不同的文件中被给定了不同的类型。
- 读者使用的c语言实现对int类型的数值与long类型的数值在内部表示上是一样的。尤其是在32位计算机上,一般都是如此处理。在这种情况下,程序很可能正常工作,就好像n在两个文件中都被声明为long (或int)类型一样。本来错误的程序因为某种巧合却能够工作,这是一个很好的例子。
- 变量n的两个实例虽然要求的存储空间的大小不同,但是它们共享存储空间的方式却恰好能够满足这样的条件:赋给其中-一个的值,对另一个也是有效的。这是有可能发生的。举例来说,如果链接器安排int 类型的n与long类型的n的低端部分共享存储空间,这样给每个long类型的n赋值,恰好相当于把其低端部分赋给了int 类型的n。本来错误的程序因为某种巧合却能够工作,这是一个比第2种情况更能说明问题的例子。
- 变量n的两个实例共享存储空间的方式,使得对其中个赋值时, 其效果相当于同时给另一个赋了完全不同的值。在这种情况下,程序将不能正常工作。
因此,保证一个特定名称的所有外部定义在每个目标模块中都有相同的类型,般来说是程序员的责任。 而且,“相同的类型” 也应该是严格意义上的相同。例如,考虑下面的程序,在一个文件中包含定义:
//demo3.c
char filename[] = "/etc/password"
而在另一个文件中包含声明:
//demo4.c
extern char* filename;
尽管在某些上下文环境中,数组与指针十分相似,但他们毕竟不同。在第一个声明中,filename 是一一个字符数组的名称。尽管在一个语句中引用filename的值将得到指向该数组起始元素的指针,但是filename的类型是“字符数组”而不是“字符指针”。在第二个声明中,filename 被确定为一个指针。这两个对filename的使用存储空间的方式是不同的。
更正:改变filename的声明或定义中的任意一个,使其与另一个类型匹配。
char filename[]="/etc/password";
extern char filename;
或者:
char *filename = "/etc/password";
extern char* filename;
练习1 假定一个程序在一个源文件中包含了声明:
long foo;
而在另一个源文件中包含了:
extern short foo;
又进一步假定,如果给long类型的foo赋一个较小的值,例如37,那么short类型的foo就同时获得了一个值 37.我们能够对运行该程序的硬件做出什么样的推断?如果short类型的foo得到的值不是37而是0.我们又能够做出什么样的推断?
答: 如果把值37赋给long型的foo,相当于同时把值37也赋给了short 型的foo那么这意味着short型的foo与long型的foo中包含了值37的有效位的部分,两者在内存中古用的是同一区域。 这有可能是因为long型和short型被实现为同类型, 但很少有c语言的实现会这样做。 更有可能的是,long型的foo的低位部分与shot型的foo共享了相同的内存空间,一般情况下, 这个部分所处的内存地址较低:因此我们的一个可能推论就是,运行该程序的硬件是一个低位优先(ittle-endian)的机器。同样道理,如果在long型的foo中存储了值37,而short 型的foo的值却是0,我们所用的硬件可能是一个 高位优先( big-endian)的机器。
endian 的意思是“数据在内存中的字节排列顺序”,表示一个字在内存中或传送过程中的字节顺序。在微处理器中,像long/DWORD 32 bit )0x12345678这样的数据总是按照高位优先方式存放的。但在内存中,数据存放顺序则因微处理器厂商的不同而不同。一种顺序称为big-endian,即把最高位字节放在最前面;另一种顺序就称为little-endian,即把最低位字节放在最前面。
big-endian:最低地址存放高位字节,可称为高位优先。内存从最低地址开始,按顺序存放。这种存放方式正是我们的书写方式,高数位数字先写(比如,总是按照千、百、十、个位来书写数字),而且所有处理器都是按照这个顺序存放数据的。
little-endian:最低地址存放低位字节,可称为低位优先。内存从最低地址开始,顺序存放。little-endian 处理器是通过硬件将内存中的little-endian排列顺序转换为寄存器的big-endian排列顺序,因此没有数据加载/存储的开销。