假设有个这样的一段代码:
#include <stdio.h>
int main ()
{
union u {
char a[4];
int b;
};
union u test;
test.b = 1;
printf("%x.%x.%x.%x\n", test.a[0],test.a[1],test.a[2],test.a[3]);
return 0;
}
在不同的机器上编译运行,结果会不一样。
x86的机器采取小端编码形式:得出的结果是:1.0.0.0;
PowerPC的机器采取大端编码形式:得出的结果时:0.0.0.1;
从整体来说有三种编码方式,大端形式、小端形式和网络形式:
大端形式:按内存地址升序的打印结果是:0.0.0.1;
小段形式:按内存地址升序的打印结果是:1.0.0.0;
网络形式:与大端相同;
大端小端是因为不同厂家各自为营的结果,网络形式是因为需要统一,方便不同CPU架构的机器之间传输数据,最后还是采取大端形式作为标准。
那么采取一下两个宏来辩别当前是大端还是小端比较方便:
const int endian = 1;
#define is_big_endian() ( (*(char*)&endian ) == 0 )
#define is_little_endian() ( (*(char*)&endian ) == 1 )
定义一个整型变量endian,初始化为1;取其变量地址&endian,然后将这个地址强转(casting)为char*型的,即(char*)&endian,然后再用*去间接访问地址(char*)&endian,即*(char*)&endian,那么就相当于那个联合体test.a[0]。
因为大端的b[0] == 0,小端的b[0] == 1,所以才能这样判断,当然前提都是int是32bits的。
扩展一下,如果int不是32bits的呢?64bits,16bits,or 8bits呢?
64bits或者32bits:那么联合体改成:
union u16 {
char a[2]; //假定char总是8bits的
int b; //假设int是16bits的
};
union u64 {
char a[8]; //假定char总是8bits的
int b; //假定int是64bits的
};
去测试的话,结果还会是,大端的机器上u.a[0] == 0,小端的机器上u.a[0] == 1;所以在64bits或者16bits上,该宏是有效的。
8bits:那么联合体改成:
union u {
char a[1]; //假定char总是8bits的
int b; //假设int是8bits的
};
去测试的话,不管大端还是小端,u.a[0] == 0,难道说bits的机子上就不适合了?
NO,如果在某个机器上int是8bits的,那么可想而知,char难道还会是8bits的吗?所以上面这个假设前提就不对,所以可能的假设是在8bits的机器上,char应该变成了4bits的。
当然,也可能我这个假设也是错误的,但是随便能碰到8bits的机器吗?甭管这么多了,16bits、32bits和64bits都搞定了,就OK了