计算机原理 - 大小端

说明

  • 大小端问题由来:《格列佛游记》小说中,小人国为水煮蛋该从大的一端(Big-End)剥开还是小的一端(Little-End)剥开而争执,争执的双方分别被称为“大端派”和“小端派”。

计算机领域

  • 大小端问题引申到计算机领域:将数据存入大于一个字节大小的内存中,例如:0x1存入4字节大小内存,数据是从内存高地址开始存储还是从内存低地址开始存储?一个字节的内存就不存在这个问题。
  • 正因为有以上争执,CPU既有采用大端模式的也有采用小端模式的,例如:arm,power,mips早期都坚持大端,但是也许是为了怕作死,也做了小端,不过由于X86是小端,大家上学时候学计算机原里大多也是学的小端,当前常用的大部分是小端模式;但是由于既有大端CPU也有小端CPU,软件需要兼容处理。

疑惑点

  1. 数据以及内存的低位高位是以bit为单位还是以byte为单位?
  • 如果以byte为单位, 如下:
0x12345678
内存地址 高 ~ 低
大端:0x78563412
小端:0x12345678
  • 如果以bit为单位,即使是单字节也会受大小端影响,如下:
0x12
内存地址 高 ~ 低
小端:0001 0010
大端:0100 1000    // 0x48
  • 由于当前手上没有大端设备,但是网络字节序是采用的大端,通过网络字节序验证如下:
int a = 0x12345678;
int b = htonl(a);
printf("%08x", b);
* 在小端设备上运行结果是:0x78563412
  • 由测试可知:数据以及内存的高位和低位是以Byte字节为单位。

特殊情况

  1. 虽然CPU既有大端也有小端,但是网络传输为了兼容,字节序采用大端模式。

理解

什么是大小端模式

  • 内存存储数据时,数据的高低位和内存地址的高低位对应关系;直白点说:内存存储数据是从低地址开始存储,还是从高地址开始存储。

区别

  • 大端模式:数据从高地址开始存储,高位数据存在于内存低位地址,低位数据存在于内存高位地址。
  • 小端模式:数据从低地址开始存储,高位数据存在于内存高位地址,低位数据存在于内存低位地址。
  • 例如:0x1存储在4Bytes内存中
内存地址: 0x03   0x02   0x01   0x00
小端: 0x00   0x00   0x00   0x01
大端: 0x01   0x00   0x00   0x00

注意点

  1. 大小端是CPU控制内存的存储方式的不同,和内存区域无关
  • 数据不管存储在栈上还是堆上,大小端是不会变化的。
  1. 大小端是CPU控制内存的存储方式的不同,并不受数据类型影响
  • 大小端是将数据存储域多个字节内存空间的存储方式,单个字节内存空间没该问题; 容易被误解为单字节类型数据不受大小端影响,只有多字节类型数据受影响。
  1. 例子
char *c = "hello world";
* 如果是小端CPU,不仅仅c指向的内存中存储的地址是按小端存储的,并且“hello world”也是按小端存储的,'h'在低地址,'d'在高地址,大端相反。

char a[10];
* a是字节数组,如果是小端CPU,a[0]在低地址,a[9]在高地址,大端相反。

char *c = "hello world";
char *p = c;
for (int i = 0; i < strlen(c); i++){
    printf("%c", *p);
    p++; 
}
* 为什么可以通过p++遍历该字符串?其实这是小端CPU上的做法,大端应该改成p--;原因:p++只是内存地址的增加,刚好匹配小端的存储方式,和大端的存储方式相反。

判断大小端

  1. 位移法
short a = 1;
(a >> 8)?printf("Big"):printf("Little");
  • 地址: 高地址 <<====== 低地址
  • 小端模式存放:0000 0001 >> 8 == 0000 0000
  • 大端模式存放:0001 0000 >> 8 == 0000 0001

个人总结

  • 网上有很多博客有描述判断大小端的方法,例如:位移法,强制转换法,共用体法,但是我对其中的几种方法存在怀疑,原因是:
  1. 博客中只看到程序在小端设备设备上的运行结果,却从来没有人使用大端设备来验证程序是否能判断正确。
  2. 感觉都是站在小端的角度思考大端。
  • 例如:
* 强制转换法
short a = 1;
char b = a;
(b)?printf("Little"):printf("Big");
  • 博客解释如下:数据类型强制转换,本质还是取低8位数;a = 1 ,变成二进制为:0000 0001,强转为char时,保留unsigned short a变量的低8位。所以这样就更加明了了。因为1低位数据,如果char c不为0,表明1存放在低位,即是小端模式;如果char c变量为0,表明1存放在高位,即是大端模式。
  • 个人理解:这里short类型转换为char类型,数据类型强制转换,本质还是取低8位数,我理解的低8位,应该是数据的低8位,而不是上面解释的内存低8位,小端数据的低8位刚好是内存的低8位,但是大端却相反,不能因为小端是内存低8位,大端就也是内存低8位;我也不认为,CPU会出现基础问题:值超出范围的数据类型强制转换,值丢失可以理解,但是数据1即在char范围内也在short范围内,强制类型转换后,值会丢失!
  • 文章的目的并不是为了学习如何判断大小端(当前常用的CPU都是小端,没有兼容的需求,判断也没意义),而是为了理解不同模式下,内存数据的存储方式。

你可能感兴趣的:(计算机原理)