引子
不知道你是否像我一样好奇过一个问题:为什么每当我们在调试查看内存窗口时,(以int类型为例)4个字节内容存储的顺序好像是倒着的。
比如下面这张图,十进制数2077转换为十六进制是0x81d,四个字节分别是:00 00 08 1d。
内存窗口里的展示就是十六进制形式的,下面的1d 08 00 00分别代表四个字节,但是为什么是存放成1d 08 00 00而非00 00 08 1d呢?
那么本文,就来为你解答这个疑问。
什么是大小端字节序?
现在我们假设有下面这个代码:
int a = 0x11223344;//十六进制数
那么,因为数据在内存中的存储以字节为单位,这个十六进制数的四个字节内放的应该就是11 22 33 44(因为1个十六进制位可以转换为4个二进制位,而8个二进制位也就是2个十六进制位刚好为一个字节),可能会有以下两种存放方式:
我们把上面这一种叫做大端字节序存储,下面的叫小端字节序存储。可以通俗地理解为,正着存的是大端,倒着存的是小端。
用语言描述这两种存储方式就是:
低位字节存放在高地址处,高位字节存放在低地址处,叫大端字节序存储;
低位字节存放在低地址处,高位字节存放在高地址处,叫小端字节序存储。
为什么会有大小端字节序之分呢?
因为在存储数据时,往往不是一个字节,如short是2个字节, int是4个字节,float是4个字节,而超过一个字节的内容在存储时,就有字节顺序的问题,哪个字节在前哪个字节在后呢?是先存高位字节、还是先存低位字节呢?
所以需要确定一个顺序,乱序的我们一般不采用,就剩下正着和反着两种主要的存储顺序。我们将正着的称为大端字节序存储,倒着的称为小端字节序存储,更具体地说就是上面所说:低位字节存放在高地址处,高位字节存放在低地址处,叫大端字节序存储;低位字节存放在低地址处,高位字节存放在高地址处,叫小端字节序存储。
可以记住的是,我们一般使用的x86结构为小端字节序存储。
写一个程序判断当前机器的字节序
那么我们现在能否写一个程序来判断当前机器的字节序呢?
这个问题需要我们对字节序的概念掌握,同时还需要我们对指针有一定了解:
假如我们现在int a=1;那么它的存储序列的十六进制形式就是00 00 00 01,如果当前机器是大端字节序,那么存储时就会是00 00 00 01,而如果是小端字节序,存储就会是01 00 00 00。只要我们拿出第一个字节的内容看看是1还是0,就能知道当前机器的字节序了,对吧。
那么现在问题转化成,我们怎么拿到第一个字节内容呢?
如果你想直接将int强制类型转化为char,(char)a,很抱歉这是不能达到预期的,为什么?因为无论存储方式是大端字节序还是小端字节序,(char)a都会拿到1,因为这种强转的实现逻辑是,取最低位的有效字节(因为char只有一个字节),因为这种逻辑能一定程度上保证强转后的准确性,否则拿0有点莫名其妙了。
那么我们应该怎么做呢?为了不拿有效数字,就拿第一个字节内容,我们可以通过地址的方式,只要我们是通过第一个字节的地址去拿这个存储内容,我们就能保证拿的是第一个字节内容。
所以问题变为怎样可以只拿一个字节的地址,现在你应该就能明白了,只要把&a,即变量a的地址强制类型转换为char*类型,我们在解引用时就会只访问一个字节内容而非4个字节(int类型)的内容了。
可能需要解释的代码就是return *(char*)&a这一句,因为我们要么拿到1要么拿到0,我们可以直接将其作为返回值,调用结果拿到1我们就输出 "当前机器是小端字节序存储",否则就输出"当前机器是大端字节序存储"。这样就行了,代码保证了简洁性。
那么,到此本文就结束了,祝阅读愉快^_^