zoukankan      html  css  js  c++  java
  • 彻底理解字节序

    假设我们有一个16位整数,那么它是由2个字节组成的。

    首先,我们引出一个概念,数据高字节数据低字节

    特别要强调的是,这里的指的是数据表示形式上的高字节和低字节,不涉及(不依赖)任何存储上的具体实现。

    因为后面我就会引入另一个概念,内存低地址内存高地址

    由于计算机内存地址的基本单位是字节,也就是说每个字节占一个地址值。

    那么16位整数需要2个自己的存储空间,即需要占用2个内存地址。

    还有两个术语是我们会经常见到的,那就是MSB(most significant bit)和LSB(least significant bit)。

    MSB和LSB都是针对数据表示形式而言的,同样也不涉及(不依赖)任何存储上的具体实现。

    MSB指的是最高有效位,是数字最左边的一位。LSB指的是最低有效位,是数字最右边一位。

    在讨论字节序问题上,如果文章上来不先把概念特别强调清楚,我们很容易产生混淆。

    下面,我们将引出这篇文章最重要的概念了,小端(little-endian)和大端(big-endian)。

    小端指的是将数据小的一端(即数据低字节)存储在起始地址(即低地址)。

    小端指的是将数据大的一端(即数据高字节)存储在起始地址(即低地址)。

     我们把某个主机的CPU所用的字节序称为主机字节序

    TCP/IP规定采用大端字节序来传送网络协议数据包中的多字节整数数据。也就是说网络字节序等于大端字节序。

    下面我们要讲解位序了。位序与字节序一般是保持一致的。

    在C语言中,位域与结构体类似,其语法规定:先声明的成员位于低地址,后声明的成员位于高地址
    那么下面的位域中:
    typedef struct OneByte
    {
    bt0 : 1;
    bt1 : 1;
    bt2 : 1;
    bt3 : 1;
    bt4 : 1;
    bt5 : 1;
    bt6 : 1;
    bt7 : 1;
    }
    成员bt0就位于一个字节中最低地址bit0处,成员bt7就位于一个字节的最地址bit7处。

    上面讲的是原理,下面讲一些具体实现。

    宏定义__BYTE_ORDER定义在glibc的endian.h中,其值要么为__LITTLE_ENDIAN,要么为__BIG_ENDIAN

    应用程序代码中可以用如下的语句来判断大小端,#if __BYTE_ORDER == __LITTLE_ENDIAN

    但是,宏定义__BYTE_ORDER不一定存在于别的libc中,因此应用程序代码中在使用__BYTE_ORDER之前还需要实现判断libc的类型。

    那么如何判断你的代码使用的libc是不是glibc呢?

    使用这个宏定义进行判断#ifdef __GLIBC__ ,

    The symbol __GLIBC__ is defined in the header features.h, and features.h is include by stdio.h

    glibc-2.19-svnr25243/libc/ports/sysdeps/unix/sysv/linux/mips/bits/endian.h

    里面通过判断__MIPSEB__还是__MIPSEL__来给__BYTE_ORDER定义不同的值。

    #ifdef __MIPSEB__
    # define __BYTE_ORDER __BIG_ENDIAN
    #else
    # ifdef __MIPSEL__
    # define __BYTE_ORDER __LITTLE_ENDIAN
    # endif
    #endif

    那么__MIPSEB__和__MIPSEL__来自何方呢?

    还是在同样的头文件中,我看到如下注释,重点是我加粗的文字。

    The MIPS architecture has selectable endianness.
    Linux/MIPS exists in two both little and big endian flavours and we
    want to be able to share the installed headerfiles between both,
    so we define __BYTE_ORDER based on GCC's predefines.

    这说明了__MIPSEB__和__MIPSEL__是定义在所用的交叉编译器里面的。

    这里总结一下,glibc的大小端定义依赖于交叉编译器的预定义设置,而应用程序判断大小端又依赖于glibc的大小端定义。

  • 相关阅读:
    ubuntu18.04安装g2o
    akka学习
    spark学习记录-2
    spark学习记录-1
    c++ string需要注意的地方
    clion server激活地址
    【转】c++面试基础
    c++反射概念-简单介绍
    死锁的理解
    c++ 反射类型
  • 原文地址:https://www.cnblogs.com/yorkwoo/p/4541151.html
Copyright © 2011-2022 走看看