分类: C/C++
2011-12-13 16:48:34
可惜记住这些,最后还是只能在用的时候死记这些,并不明白其中含义,所以在网上查阅了一些相关资料,增加了一点对于字节序的认识。
不看不知道,一看还蛮有趣的关于endian的来源:
ps:大师们的涉猎真是广啊!
对于主机中的字节序,个人觉得其实字节序是指CPU从输入设备中获得数据写入到内存中的顺序。当然是对于该数据是大于设备内存的存储单位的(一般为8bites),如果一个数据是小于等于一个字节的,那它也就没有什么所谓的字节序了,内存中直接分配一个单位给它就能储存它所表示的值了。
(ps:上述的想麻烦牛人们正确讲解一下)
看下面的代码:
运行结果:
从运行结果中我们可以看到,在union 结构 a 中 i 和 x的内存地址是一样的,这个符合一般我们对于union 的理解。数组x中数据存储在内存中也是按照写入的顺序从低地址到高地址储存。(如结果中的x[3],和x[4]的地址可以看出,因为char是一个字节的,所以存储时不关心字节序)。而 最终 i 输出的值是多少则是由主机的cpu到底属于哪个架构决定的。(本台机器是x86的,是Little-endian)
这里先了解一下在大小端的情况下到底CPU是按照怎么样的顺序读取内存中的数据:
先认识一下基本的知识,关于高低字节和高低位,
高低位是相对于内存中数据存储的地址的高低,如下图:(ps:摘自网络32byte)
这里如上例中的a.x[5],由于x[5]是由栈已分配好的,所以x[4],x[3],x[2],x[1],x[0]已经在栈中有各自的地址:
栈底 (高地址)
----------
x[4]
x[3]
x[2]
x[1]
x[0]
----------
栈顶 (低地址)
这个可以从运行结果得到验证。
高低字节则是指例如一个数 int a = 0x01020304,那么高字节到低字节依次是1 2 3 4.
了解了高低位和高低字节后看下面的例子
例子是WIKI百科中的一个例子:
以十六字节的数据为例:0A0B0C0D (该数据对应的是从高地址地址到低地址,即0A是高地址,0D是低地址)
大端:
存储单位为8bites
地址增长方向 → | |||||
... | 0x0A | 0x0B | 0x0C | 0x0D | ... |
储存单位为16bites
increasing addresses → | |||||
... | 0A0Bh | 0C0Dh | ... |
可以看到大端字节序把0A0B0C0D存储到内存中是把高字节的0A储存在内存中的低地址位,而低字节0D则是在高地址位。
小端字节序:
储存单位为8bites
increasing addresses → | |||||
... | 0Dh | 0Ch | 0Bh | 0Ah | ... |
存储单位为16bites
increasing addresses → | |||||
... | 0C0Dh | 0A0Bh | ... |
很明显可以看出此时小端字节序和大端正好相反,把高字节的0A放在内存的高地址位,低字节的0D放在低地址位。
在了解了下字节序后,可以来解决这个最初代码中的那个x.i的值的问题了:
union中 i 和 x 是共用一段内存区域的,所以它们的首地址是一样的。
x[5] 在内存中的分布是
栈底 (高地址)
----------
x[4] 01 x[3] 02
x[2] 03
x[1] 04
x[0] 05
----------
栈顶 (低地址)
由于都是一个字节的所以没有所谓的字节序。当要通过a.i 取值时,由于i 是int类型占四个字节,所以相应的 i 会取从起始位置x[0]开始的四个字节依次是 05 04 03 02 。由于是小端字节序,所以应该高地址位对于高字节,所以 i 的值是 i = 2030405;(十六进制表示)。
感觉这个例子不好理解,其实应该修改程序,把给x[5]赋值换成给i 赋值更能直接的表达小端字节序是怎么存储的。
修改代码:
运行结果为:
有兴趣可以分析,理解一下这个结果。
有关字节序可以查看wiki中的文章:
英文版:
中文版:
ps: 希望有理解错误的地方能够帮忙指正!
添加一个实例:
试题1:请写一个C函数,若处理器是Big_endian的,则返回0;若是Little_endian的,则返回1
解答:
int checkCPU()
{
{
union w
{
int a;
char b;
} c;
c.a = 1;
return (c.b == 1);
}
}
剖析:
嵌入式系统开发者应该对Little-endian和Big-endian模式非常了解。采用Little-endian模式的CPU对操作数的存放方 式是从低字节到高字节,而Big-endian模式对操作数的存放方式是从高字节到低字节。例如,16bit宽的数0x1234在Little- endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址 存放内容
0x4000 0x34
0x4001 0x12
而在Big-endian模式CPU内存中的存放方式则为:
内存地址 存放内容
0x4000 0x12
0x4001 0x34
32bit宽的数0x12345678在Little-endian模式CPU内存中的存放方式(假设从地址0x4000开始存放)为:
内存地址 存放内容
0x4000 0x78
0x4001 0x56
0x4002 0x34
0x4003 0x12
而在Big-endian模式CPU内存中的存放方式则为:
内存地址 存放内容
0x4000 0x12
0x4001 0x34
0x4002 0x56
0x4003 0x78
联合体union的存放顺序是所有成员都从低地址开始存放,面试者的解答利用该特性,轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写。