基础02:内存的大小端


本文介绍内存的大小端,中间有一段代码需要有一点点C语言基础。

源头

内存的大小端,始于鸡蛋的大小端,你信么?至于你信不信,我反正信了。
Jonathan Swift的《格列佛游记》(Gulliver’s Travels):Lilliput和Blefuscu这两个强国在过去的36个月中一直在苦战。战争的原因:大家都知道,吃鸡蛋的时候,原始的方法是打破鸡蛋较大的一端,可以那时的皇帝的祖父由于小时侯吃鸡蛋,按这种方法把手指弄破了,因此他的父亲,就下令,命令所有的子民吃鸡蛋的时候,必须先打破鸡蛋较小的一端,违令者重罚。然后老百姓对此法令极为反感,期间发生了多次叛乱,其中一个皇帝因此送命,另一个丢了王位,产生叛乱的原因就是另一个国家Blefuscu的国王大臣煽动起来的,叛乱平息后,就逃到这个帝国避难。据估计,先后几次有11000余人情愿死也不肯去打破鸡蛋较小的端吃鸡蛋。Danny Cohen一位网络协议的开创者,第一次使用这两个术语指代字节顺序,后来就被大家广泛接受。

大小端的定义

小端(Little-Endian)就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
大端(Big-Endian)就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
举个栗子:
如果int num = 0x12345678,那么大小端的存放方式分别如下表。

-> ->
内存地址 0xd99c 0xd99d 0xd99e 0xd99f
大端 12 34 56 78
小端 78 56 34 12

大小端的优势

小端模式 :强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
大端模式 :符号位的判定固定为第一个字节,容易判断正负。

常见的大小端

一般操作系统都是小端,而通讯协议、Java是大端的。
CPU方面:
大端 : PowerPC、IBM、Sun
小端 : x86、DEC、DSP
ARM既可以工作在大端模式,也可以工作在小端模式,根据可以由硬件来选择。

判断大小端的代码

通过int最低内存地址进行判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 文件名: endian1.c
* 通过int最低内存地址的字节转换成char进行判断
*/

#include <stdio.h>

int main()
{
int num = 0x12345678;
char n0 = ((char *) &num)[0];
char n1 = ((char *) &num)[1];
char n2 = ((char *) &num)[2];
char n3 = ((char *) &num)[3];

if (n0 == 0x12) {
printf("this is Big Endian\n");
} else {
printf("this is Little Endian\n");
}

// 内存从低到高分别打印四个字节的内容
printf("%p: 0x%x\n", &((char *) &num)[0], n0);
printf("%p: 0x%x\n", &((char *) &num)[1], n1);
printf("%p: 0x%x\n", &((char *) &num)[2], n2);
printf("%p: 0x%x\n", &((char *) &num)[3], n3);
return 0;
}

CentOS7下运行结果如下。

1
2
3
4
5
6
7
$ gcc endian1.c
$ ./a.out
this is Little Endian
0x7fff4a359ad8: 0x78
0x7fff4a359ad9: 0x56
0x7fff4a359ada: 0x34
0x7fff4a359adb: 0x12

通过联合体进行判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 文件名: endian2.c
* 通过联合体进行判断
* 联合体union的存放顺序是所有成员都从低地址开始存放
*/
#include <stdio.h>

int main()
{
union NUM {
int a;
char b;
} num;

num.a = 0x12345678;

if (num.b == 0x12) {
printf("this is Big Endian\n");
} else {
printf("this is Little Endian\n");
}

return 0;
}

CentOS7下运行结果如下。

1
2
3
$ gcc endian2.c  
$ ./a.out
this is Little Endian

总结

  1. 如果内从从低到高,那么小端模式与日常看到顺序的相反,大端模式则相同。
  2. x86是小端模式。

如果本文对你有所帮助,请小额赞助
~~ EOF ~~