计算机的大小端

计算机的大小端指的是不同的字节顺序储存方式。

0x1A2B3C4D,总共四个字节,两个十六进制数表示一个字节,高位字节为0x1A,低位字节为0x4D;中间两个字节分别为0x2B和0x3C;数值0x1A2B3C4D想要在计算机中正确使用,就必须要考虑在内存中将其对应的四个字节合理存储。

对于一个数值多个字节顺序存储就有两种存储方式:

  • 大端:(Big-Endian):就是把数值的高位字节放在内存的低位地址上,把数值的低位字节放在内存的高位地址上(低字节在后,高字节在前)
    • 人类习惯读写大端字节序,比如1234 -> 一千两百三十四。
    • 除了计算机的内部处理,其他的场合几乎都是大端字节序,比如网络传输和文件储存
    • 优点:符号位的判定固定为第一个字节,容易判断正负。高位字节也容易进行大小对比
举例:
内存低地址 --------------------> 内存高地址
0x1A | 0x2B | 0x3C | 0x4D
高位字节 <-------------------- 低位字节
  • 小端:Little-Endian):就是把数值的高位字节放在高位的地址上,低位字节放在低位地址上(低字节在前,高字节在后)
    • 为什么会有小端字节序?计算机电路先处理低位字节,效率比较高,因为计算都是从低位开始的。所以,计算机的内部处理都是小端字节序。
    • 123 + 342 -> 先从个位开始算,再十位,百位
    • 优点:强制转换数据不需要调整字节内容,1、2、4字节的存储方式一样。
举例:
内存低地址 --------------------> 内存高地址
0x4D | 0x3C | 0x2B | 0x1A
低位字节 --------------------> 高位字节

注意:

  1. 不管是大端法还是小端法存储,计算机在内存中存放数据的顺序都是从地址到高地址所不同的是首先取低字节的数据存放在低地址还是取高字节数据存放在低地址。
  2. 大小端是数据在存储时的表现,而不是在寄存器中参与运算时的表现
  3. 计算机处理字节序的时候,不知道什么是高位字节,什么是低位字节,也并不存在所谓的数据类型,比如char,int等。它只知道按顺序读取字节,先读第一个字节,再读第二个字节,如果是大端字节序,先读到的就是高位字节,后读到的就是低位字节。小端字节序正好相反
  4. 所谓的数据类型,比如char,int等,在代码中的作用就是让编译器知道每次应该从那个地址起始读取多少位的数据,赋值给相应的变量

举例,16位整数:

buf是整个数据块在内存中的起始地址,offset是当前正在读取的位置

大端:第一个字节((高位字节)左移8位(即后面添8个0),然后再与第二个字节进行或运算。

x = buf[offset] << 8 | buf[offset+1];

小端:第二个字节左移8位,然后再与第一个字节(低位字节)进行或运算。

x = buf[offset+1] << 8 | buf[offset];

如何用代码检测用的是大端还是小端

  • 借助联合体union的特性实现(union类型数据所占的内存空间等于其最大的成员所占的空间,
int main(){
    union{
      int a;  //4 bytes      
      char b; //1 byte    
    } data;

    data.a = 1; //占4 bytes,十六进制可表示为 0x 00 00 00 01高字节->低字节
                     //b因为是char型只占1Byte,a因为是int型占4Byte   
                     //所以,在联合体data所占内存中,b所占内存等于a所占内存的低地址部分     
    if(1 == data.b){ //走该case说明a的低字节,被取给到了b,即a的低字节存在了联合体所占内存的(起始)低地址,符合小端模式特征      
        printf("Little_Endian\n");
     } else { 0 == data.b
        printf("Big_Endian\n");
     }
   return 0;
}
  • 通过将int强制类型转换成char单字节,判断起始存储位置内容实现
int main(){
    int a = 1; //占4 bytes,十六进制可表示为 0x 00 00 00 01    
                   //b相当于取了a的低地址部分     
     char *b =(char *)&a; //占1 byte    
      if (1 == *b) {//走该case说明a的低字节,被取给到了b,即a的低字节对应a所占内存的低地址,符合小端模式特征        
          printf("Little_Endian!\n");
    } else {
          printf("Big_Endian!\n");
    }
    return 0;
}

 

Reference:

  1. https://www.jianshu.com/p/633b52b7baec
  2. https://www.ruanyifeng.com/blog/2016/11/byte-order.html
posted @ 2022-03-20 19:26  cancantrbl  阅读(1591)  评论(0编辑  收藏  举报