如何判断当前环境的存储方式是大端模式还是小端模式?

一、形象的内存格子。
1、我们都知道数据是可以存储在内存中的,但是它究竟是以一种什么样的形式存储呢?这里我们引入一个“内存格子”来形象化数据的存储。在一个32位计算机中,假设一个格子代表一个字节,则四个字节的单元格是这样的:

0000 0000 0000 0000 0000 0000 0000 0000

刚刚好一个字节8个位,四个字节四个格子就是32位了,这也是为什么在32位机下一个int类型是4个字节了,int就是整型,是以当前的多少位机来说的,如果是64位则int类型是8个字节的。

二、内存格子的地址。
1、上面已经说了一个字节是一个格子来表示,而每个格子又有8个位,但是当我们要读取某个格子的数据时是怎么读取的呢?答案就是按地址寻址,CPU会为每个内存格子都分配一个地址,地址是从左到右由低变高的。假如存储一个1个字节的类型数据,我们只需要那个格子的地址;如果是一个变量是需要占用4个字节数据呢?占了四个格子的地址到底是用哪个地址访问?答案就是按4个格子中的首格子的地址,也叫首地址。所以在32位机中,定义int a[10],会发现a[0]的地址和a[1]的地址不是相差1,而是相差4,因为a[0]占了4个字节,取其首地址,a[1]也是占了4个字节,取其首地址,刚刚好就是相差4了。

三、大小端模式。
1、小端模式:当一个数的二进制的高位存在内存格子的高地址的格子中,或者是低位存储在低地址的格子中,它就叫小端模式。

2、大端模式:个小端模式相反,就是数据的高位放在了低地址的内存格子中,或者是数据的低位放在了高地址的内存格子中。

3、如何理解呢?举个例子:32位机下,如果int a = 1,那个1的二进制是0000 0000 0000 0001(这是我们写出来的),但是它在计算机存储的时候不一定是这样子,有两种可能,如下:

0000 0000 0000 0000 0000 0000 0000 0001
1000 0000 0000 0000 0000 0000 0000 0000

那么,我们看见这两种方式中,第一种存储的方式是1的二进制的低位是放在了第一个格子(也就是低地址的格子),所以第一种就是小端模式的存储。再看第二个,1的二进制的低位是放在了最后一个格子(也就是高地址的格子),所以第二种就是大端模式的存储了。

四、如何判断当前环境的存储方式是大端模式还是小端模式?

1、使用共用体的方法判断。

#include <stdio.h>
union test
{
    int a; 
    char b;
};
int main(void)
{
    union test t1;
    t1.a = 1;
    if(t1.b == 1)
    {
        printf("小端模式\n");
    }
    else
    {
        printf("大端模式\n");
    }
    return 0;
}

代码检验的大概思路是:定义一个共用体,因为共用体是里面所有的变量共用同一块内存的,当int a=1时,根据上述可知1可能有两种存储方式:

0000 0000 0000 0000 0000 0000 0000 0001
1000 0000 0000 0000 0000 0000 0000 0000

然后,char类型的b跟a是共用内存的,而且b是一个字节长度的,所以b肯定是第一个格子里面的内容,所以判断b到底是0还是1就相当于判断第一个格子是0还是1,就可得出最低位是存储在地址最高位的格子还是地址最低位的格子了,从而可以判断出来大端模式还是小端模式。

2、使用指针法判断。

#include <stdio.h>
int main(void)
{
    int a = 1;  
    char *pa = (char*)(&a);
    if((*pa) == 1)
    {
        printf("小端模式\n");
    }
    else
    {
        printf("大端模式\n");
    }
    return 0;
}

代码检验的大概思路是:跟上面的原理一样,首先定义int a =1;然后用char类型的指针去访问这块内存,char类型的指针也是肯定是读取的是第一个格子的内容,如果是1则说明低位就是放在低地址中,是小端模式,否则是大端模式。

3、一些看似可以测试大小端模式但是实际不可以的方式:
(1)位与、位或

    int a = 1;
    int b;
    b = a & 0x01;       // 判断是1还是0来判断

原因:当进行 a & 0x01时,a已经是从内存读取出来的而不是直接在内存的层面上进行&,所以不可取。

(2)移位

    int a = 1;
    int b;
    b = a>>1;           // 通过右移得出是1还是0判断

原因:当进行 a>>1时,a已经是从内存读取出来的而不是直接在内存的层面上进行>>,所以也不可取。

(3)强制类型转换

    int a = 1;
    char b;
    b = (char)a;        // 通过强制类型转换得出是1还是0判断

原因:同上,在进行强制类型转换的时候,a是从内存中读取出来是什么数,然后再进行强制类型转换的,这也是没有意义的。

五、总结。
1、我们发现,不是所有的方法都可以检验大小端模式的,如果运算层次属于C语言层次的运算,都需要先从内存读取这个数来进行运算的,并不是直接在内存的层次进行,这样的方法都不可。

2、像指针跟共用体那样,对这段数据是从内存中读出来的那一刻就可知道它是什么模式,而不是读出来然后再运算。

发布了24 篇原创文章 · 获赞 27 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/gyyu32g/article/details/79097169