大小端判断(联合体 & 指针)

所谓大小端:

【大端模式】 CPU对操作数的存放方式是高地址存放低位,低地址存放高位。

【小端模式】CPU对操作数的存放方式是高地址存放高位,低地址存放低位。

大多数ARM处理器都是采用的小端模式,PowerPC是采用的大端模式,网络字节序是采用的大端模式。

判断方式——编码实现:
1、使用C语言中的联合体
#include<stdio.h>
union var
{
        char c[4];
        int i;
};

int main()
{
        union var data;
        data.c[0] = 0x04;//因为是char类型,数字不要太大,算算ascii的范围~
        data.c[1] = 0x03;//写成16进制为了方便直接打印内存中的值对比
        data.c[2] = 0x02;
        data.c[3] = 0x11;
//数组中下标低的,地址也低,按地址从低到高,内存内容依次为:04,03,02,11。总共四字节!
//而把四个字节作为一个整体(不分类型,直接打印十六进制),应该从内存高地址到低地址看,0x11020304,低位04放在低地址上。
        printf("%x\n",data.i);
}

结果:
11020304
证明我的32位linux是小端(little-endian)

  • 顺便说说联合体的使用场景:

这种union的使用场合,是各数据类型各变量占用空间差不多并且对各变量同时使用要求不高的场合(单从内存使用上,我觉得没错)。

  • 联合体本质&进阶:

根据union固定首地址和union按最大需求开辟一段内存空间两个特征,可以发现,所有表面的定义都是虚的,所谓联合体union,就是在内存给你划了一个足够用的空间,至于你怎么玩~它不管~!(何止是union和struct,C不就是玩地址么,所以使用C灵活,也容易犯错)

没错,union的成员变量是相当于开辟了几个访问途径(即union包含的变量)!但是,没开辟的访问方式就不能用了?当然也能用!

写个小测试:

#include<stdio.h>
union u
{
        int i;
        double d;//这个union有8字节大小
};
main()
{
        union u uu;
        uu.i = 10;
        printf("%d\n",uu.i);

        char * c;
        c = (char *)&uu;//把union的首地址赋值、强转成char类型
        c[0] = 'a';
        c[1] = 'b';
        c[2] = 'c';
        c[3] = '\0';
        c[4] = 'd';
        c[5] = 'e';
//最多能到c[7]
        printf("%s\n",c);//利用结束符'\0'打印字符串"abc"
        printf("%c %c %c %c %c %c\n",c[0],c[1],c[2],c[3],c[4],c[5]);
}

结构体只定义了int和double“接口”,只要我获得地址,往里边扔什么数据谁管得到?这就是C语言(不止union)的本质——只管开辟一段空间。

但是你获取地址并访问和存取的数据,最好确定是合法(语法)合理(用途符合)的地址,不然虽然能操作,后患无穷,C的头疼之处,可能出了问题你都找不到。

2、使用指针方式判断大小端
void checkPoint(void)
{
    int i = 1;
    char *pointer;
    pointer = (char *)&i;

    if (*pointer==1)
        printf("litttle_endian");
    else
        printf("big endian/n");
}

如果小端方式中(i占至少两个字节的长度)则i所分配的内存最小地址那个字节中就存着1,其他字节是0.大端的话则1在i的最高地址字节 处存放,char是一个字节,所以强制将char型量p指向i则p指向的一定是i的最低地址,那么就可以判断p中的值是不是1来确定是不是小端。

猜你喜欢

转载自blog.csdn.net/m0_37925202/article/details/81412379
今日推荐