美文网首页
字节序、比特序、大端、小端

字节序、比特序、大端、小端

作者: 梦落迹南天 | 来源:发表于2020-07-20 21:22 被阅读0次

    梗概

    本文介绍了字节序和比特序中的大端和小端,不同的cpu架构有不同的内存数据读写方式,但程序的数值计算发生在寄存器上,cpu通过在寄存器和内存的数据传输转换中对用户隐藏了大端小端;数据在网络中发送的时候会统一转成大端,在主机接收的时候根据主机的CPU架构自行转换,这维护了不同CPU架构下的数据通信;但仍有缺陷的是,如果在跨平台的程序中使用了位域,由于涉及到比特序块数据反转问题,需要手动处理。

    字节序: 大端数和小端数

    大端数(big-endian)和小端数(little-endian)是两种不同的数据存储方式,这两个中文会让人绕晕,从英文上是比较好理解的。

    big-endian:大的部分(数的高位)在存储单元的尾部
    little-endian:小的部分(数的低位)在存储单元的尾部

    来看一张内存图, 从内存单元上来看排列顺序是这样的,也就是从下往上增长,从右往左增长,当一个指针指向一个int型(四内存单元)的变量时,指针的地址是地址最低的内存单元,CPU从内存中取数的时候是永远都是从最低位(右边)开始一个字节一个字节的取,将它放到寄存器中(寄存器永远是符合人类直觉的LE little-endian存储方式, 内存上的大小端存储经过CPU的加载到寄存器时被转换成LE little-endian, 从而隐藏了内存上的大小端),最左边是就是取一个数的尾部.


    image.png

    所以就很好理解了,对于一个数int a=0x01020304

    内存地址 0x00000004 0x00000003 0x00000002 0x00000001
    big-endian 04 03 02 01
    little-endian 01 02 03 04

    而字节序在CPU与程序中的本质是,字节序是在数据的存储字节大于1的时候,从内存加载一个字节到寄存器上的不同加载方式, 但使用数据的时候,无论是读short ,int 还是long long最终真正使用的是寄存器上的le little endian 的值,所以大小端对人是隐藏的,但当你一个一个去看内存的值的时候,就是直接加载到最低位,这时候就不同了。


    image.png

    验证机器是big-endian还是little-endian

    union num{
    int temp;
    char c[4];
    };
    
    int main(){
    
    union num number;
    number.temp = 0x01020304;
    
    cout<<int(number.c[3])<<endl; //如果是1则是小端,4是大端
        return 0;
    }
    

    网络传输中的字节序

    网络中传输的字节序统一为big endian,主机上的数据在send的时候会通过hton进行转换,到接收端recv的时候ntoh恢复回来,如果hton在big endian架构的系统上是一个空宏

    比特序

    字节序是在数据的存储字节大于1的时候,从内存加载一个字节到寄存器上的不同加载方式。而比特序,则是加载一个8位的bit的时候到寄存器上的不同方式,一般而言比特序和主机的字节序保持一致是大端或者小端


    image.png image.png

    网络传输中的比特序和跨平台程序

    网络传输过程中,传输协议做了hton的字节序转换,而网卡则会替我们将比特序统一转换到大端,接收端网卡接收的时候根据自己的cpu架构进行转换,对于cpu,内存而言也是不可见的;但是在使用c的位域的时候,会出现问题,对于如下的结构体,

    struct A{
         uint16_t first:4;
         uint16_t second:4;
    }A;
    

    从小端序传到大端序的主机上,比特序发生的倒序,cpu在读取的进寄存器时候可以解决,但是 first 和 second对应数值的比特块却完全颠倒了,这就需要手动矫正:


    image.png

    所以在涉及到位域的跨平台设计中常会看到如下内容,如此一来,在不同平台下,就会发生反转

    struct A{
    #if defined(__LITTLE_ENDIAN_BITFIELD)
         uint16_t first:4;
         uint16_t second:4;
    #elif defined (__BIG_ENDIAN_BITFIELD)
         uint16_t second:4;
         uint16_t first:4;
    }A;
    
    image.png

    具体参考:
    https://www.linuxjournal.com/article/6788
    https://blog.csdn.net/liuxingen/article/details/45420455/

    相关文章

      网友评论

          本文标题:字节序、比特序、大端、小端

          本文链接:https://www.haomeiwen.com/subject/ffanyctx.html