数据在内存中的存储<C语言>
杨树与晨光 2024-06-23 12:35:18 阅读 93
导言
在计算机中不同类型的数据在计算机内部存储形式各不相同,弄懂各种数据在计算机内部存储形式是有必要的,C语言的学习不能浮于表面,更要锻炼我们的“内功”,将来在写程序的时候遇见各种稀奇古怪的bug时,也便能迎刃而解,所以本文将着重介绍,整数在内存中的存储、大小端字节序和判断、浮点数的存储。
整数在内存中的存储
这部分的内容在前面已经讲过,现在让我们来复习一下:
一个数的二进制表示方法有三种:原码、反码、补码
原码:直接将数转为2进制序列,得到的就是原码
反码:符号位不变,将其它位取反
补码:在反码基础上+1
在C语言中整数可分为有符号整数和无符号整数
有符号整数:有符号位(第一位),0为正、1为负
有符号整数:没有符号位,即全为正数。
在计算机内部存放的是补码,为啥是补码?
因为CPU只有加法器,在计算机内部,正数的补码是本身,负数补码符号位不变,其他位取反,存放补码可实现加减法的统一运算(不需要添加减法器):
//在计算机内部存放的是补码,为啥是补码?int main() {int a = 9;//a的补码:00000000 00000000 00000000 00001001int b = 4;//b的补码:00000000 00000000 00000000 00000100int c = a - b;//c=a-b会被转化为c=a+(-b)// a的补码:00000000 00000000 00000000 00001001//-b的补码:11111111 11111111 11111111 11111100// c的补码 100000000 00000000 00000000 00000101//相加结果多出一位,int型只有4字节、32位,高位抛弃// c的补码: 00000000 00000000 00000000 00000101//正数原反补相同,10进制数为5printf("%d", c);return 0;}
运行结果:
大小端字节序和判断
超过一个字节的数据在存储时就会有存储顺序的问题:
通过调试观察一个整型在内存中的存储可知:a的低位存储在低地址处,当前平台属于小端存储模式。
大端存储模式:
是指数据的低位字节存储在内存空间的高位地址处。(大对大)
小端存储模式:
是指数据的低位字节存储在内存空间的低位地址处。(小对小)
为了更好的理解下面给出几道练习:
练习1(百度笔试10分)
简述大端字节序和小端字节序的概念,设计一个程序来判断当前机器的字节序。
练习2
以下代码输出结果是啥?
#include <stdio.h>//X86环境 ⼩端字节序 int main(){int a[4] = { 1, 2, 3, 4 };int* ptr1 = (int*)(&a + 1);int* ptr2 = (int*)((int)a + 1);printf("%x,%x", ptr1[-1], *ptr2);return 0;}
运行结果:
分析一下:
#include <stdio.h>//X86环境 ⼩端字节序 int main(){int a[4] = { 1, 2, 3, 4 };int* ptr1 = (int*)(&a + 1); //&a取出整个整个数组的地址(访问权限为4*sizeof(int)个字节),再加1到元素4的后面int* ptr2 = (int*)((int)a + 1); //(int)a:将地址转为int类型的数,并加1,就是加了一个字节 //因为当前平台为小端字节序,加1跳过了01,并从第二个字节开始00 00 00 02printf("%x,%x", ptr1[-1], *ptr2); //ptr[-1],访问权限为int型,倒退4字节,来到4的起始地址并打印 //*ptr2:00 00 00 02,因为平台为小端字节序,所以该数为2000000return 0;}
浮点数的存储
浮点数的存储是比较特殊的,因为它具有小数位,如果采用整数存储方法肯定是不行的,于是IEEE(国际电气和电子工程协会)754规定,任意一个浮点数V可以表示为下面这种形式:
●-1的S次方:符号位,S为1时负数,S为0时正数
●M:有效数字,M大于1小于2
●E:指数位
如10进制数5.5转为二进制数101.1
那么S=1
M=1.011
E=2
浮点数在存储时就是存储的SME,值得注意的是,常见浮点数float和double型的字节长度是不一样的,那么在存储时,SME的内存分配会有所不同:
注意点:
●前⾯说过, 1≤M,也就是说,M可以写成 1.xxxxxx 的形式,其中 xxxxxx 表⽰⼩数部分。 因此1.可以舍去。
●指数E,E为一个无符号整数,为了能存负数,754规定:存入内存时E的真实值必须再加上一个中间数,float:127,double:1023
举例:
#include <stdio.h>int main(){int n = 9;//小端字节序:00001001 00000000 00000000 00000000float* pFloat = (float*)&n;//转为float,但是存储的数据没有发生变化,依旧是00001001 00000000 00000000 00000000printf("n的值为:%d\n", n);//9printf("*pFloat的值为:%f\n", *pFloat);//0.000000//以%f的形式打印,那么会把这个数据float的方式读取,也就是SEM的形式//0 0001001 000000000000000000000000=1.0*2的(9-127)次方,无限接近于0*pFloat = 9.0;//以浮点数存储也就是0 10000010 00100000000000000000000printf("num的值为:%d\n", n);//将0 10000010 00100000000000000000000以整数形式读取也就是1,091,567,616printf("*pFloat的值为:%f\n", *pFloat);//9.000000return 0;}
运行结果:
值得注意的是在浮点数存储的时候,E有几种特殊情况:
●E全为0时,还原成2进制数时,还要减去中间数,那么这个值就会无限的小(并且M不会加上省略的1),接近于0,超出数据表示范围
●E全为1时,还原成2进制数时,255减去中间数,指数E为255,那么这个值就会无限的大,超出数据表示范围
声明
本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。