C语言进阶几分钟带你理解大小端存储模式
正片开始
C语言中数据类型的存储是较为严谨的,一块空间只能存储一种数据类型,要知道内存这个东西,在早期可是非常珍贵的。
尤其对于那些性能不好计算机更是如此,比如 Office1997,操作系统为Windows95 ,奔腾1的cpu,内存只有128M。就这么绿豆点大的存储空间,要想达到节约,利用最大化就必须在同一块空间中存入不同类型数据。
所以共用体的概念就随之产生,将几种不同类型的内容覆盖到同一内存单元,之前在我的一篇共用体专题写过,但感觉自己总结的还不够到位,这里再讲讲。
共用体原理
共用体和结构体非常相似,共用体定义很简单,只需要 union + 共用体名即可,举个栗子:
union student: { char name; short age; int weight; char sex; };
某种意义上,共用体与结构体是差不多的数据结构,他们都可以同时包含多种数据类型。
但是!毕竟不叫同一个名儿就不是同一个玩意儿,那他们==本质上的区别是啥?==这里我先从内存方面下手,对于结构体,在内存中,他们有各自的存储空间,不管这个这个成员我有没有去使用他,C语言程序都会给他分配空间, 所以有结构体类型长度大于或等于各成员长度之和一说。
而在共用体中,各成员在一坨空间里面,空间相当于是共享的的公共空间,一个共用体类型长度等于所有成员变量中最宽数据的长度,比如我刚刚的student 这个共用体中 ,有 char,short和 int 类型,此时该共用体类型长度就是4个字节,也就是 int 类型长度。强调一下,这里的共享并不是把多个变量同时放入一个共用体内,是指该共用体可被赋予任何一种变量的值,但每次赋值只能赋一种,多种还是会遵循共用体最长数据覆盖原则,也就是说共用体在同一时间只能存放一个变量。
引申一下
为了去确定当前计算机的存储模式,我们可以用共用体去试触,判断它是大端存储还是小端存储,这样简单又高效。
我们都知道计算机内存是以字节为单位的划分的,每个地址单元对应一个字节,一个字节占 8 个 bit 位,一个 bit 对应存储一个二进制数据,比如 00000000;
另外还有 int ,long ,long long,在16位和32位处理器中,可同时处理16 bit 和32 bit 的数据,寄存器宽度都大于一个字节,就此我们的大小端存储模式应运而生。
字节顺序
在搞清楚大小端模式之前必须搞清楚字节的顺序,在两个设备之间进行数据的传输时,我要把一个东西从A传到B,但这时发现在A设备中,内容是正序的,但是B设备中的内容是反序放着的,我们就无法在传输后得到正确的格式,所以就要要求统一的模式。
大小端存储
大端存储是指数据的低位字节顺序会存储在内存的高地址中,小端存储模式则恰恰相反,比如我将一个十六进制数 0x1234ffff,对应字节序由低到高从 f 到 1 ,从右向左依次读取较低位字节放在地址较大的内存单元中,如下:
小端存储则会从右向左依次读取较低位的字节存入地址较小的内存单元中。
我们常用的X86结构,ARM就是小端模式,什么 C51则为大端模式(没学我也不知道是个啥,但还是摆出来)。
共用体判断大小端
union num { int a; char b[2]; };
比如我定义一个num共用体类型,再创建一个共用体变量 union num i,这时内存中会划分出四个字节的大小用于存放 num1;假设i的char类型 i.b = 0x1234,虽然这时我num1中的char类型没有被赋值,但已经被我的 int 类型所覆盖, 我们int 类型四个字节对应四个空间,char类型只需一个空间,我们只需要观察int的值是否在char空间中高位存放了低位字节,是则为大端存储,反之则为小端存储,可用代码打印如下:
printf("i.a = %x\n",i.a); printf("i.b[0] = %x\n",i.b[0]); printf("i.b[1] = %x\n",i.b[1]);
效果如图:
可以看出我的电脑就是小端存储滴。