深入了解c语言数据类型在内存中的储存
文章目录
程序员如何修内功?
老话说得好,程序员有三种境界。
第一种:看代码是代码;?这是编程初学者
第二种:看代码是内存;?进阶学者,对代码有了更深层次的理解,也是所谓的修内功
第三种:看代码还是代码。?有点返璞归真的味道哈哈,资深老程序员了
对于我们编程初学者来说,要逐渐重视自身内功了,也就是要懂得代码在内存是怎样存储的,这非常有助于我们更好地理解代码,下面我将从四个方面深度剖析数据在内存中的存储。
1.数据的类型
2.整型在内存中的存储,如原码,反码,补码。
3.大小端字节序
4.浮点数在内存中的存储
数据的类型
char //字符数据类型
short //短整型
int //整形
long //长整型
long long //更长的整形
float //单精度浮点数
double //双精度浮点数
前五个为整型,char int short long long long
可为有符号整型signed char / int / short / long / long long和无符号unsigned
float double 浮点数(精度不同)
除了以上这些还有指针类型,结构体,联合体等,这里不细讲,主要讲整型和浮点型。
整型在内存中的存储
整型数据在内存中是以二进制存储的,接下来我们要了解三个概念,原码,反码,和补码
int 整型在内存中的大小是4个字节,也就是32个比特
如int a=9; 9是正数,数据在内存中是以补码存储的,正数原反补同型
9的原码是 00000000 00000000 00000000 00001001
原码第一位是符号数,符号数为0为正数,1 则为负数
如负数 -9 原码是 10000000 00000000 00000000 00001001
反码 11111111 11111111 11111111 11110110 符号位不变,其余取反
补码 11111111 11111111 11111111 11110111 反码加一
数据在内存中是以补码存储 ,这是为了方便计算机计算,计算机只有加法,
补码可以直接相加,再转化为原码;
此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
做一道题来巩固一下吧!
//输出什么?#include int main(){ char a= -1; signed char b=-1; unsigned char c=-1; printf("a=%d,b=%d,c=%d",a,b,c); return 0; }
运行结果是
惊不惊喜,意不意外?
这又涉及到新的内容,整型截取再整形提升
因为char类型·大小只有一个字节,而整数有4个字节
-1的补码为 11111111 11111111 11111111 11111111
所以char a拿了-1的最低位字节11111111
接着要打印%d的话就会进行整形提升,
如果是有符号字符,最高位为1则补1,0则补0,
所以signed char b整形提升后还是-1的补码。
如果是无符号unsigned char 进行整形提升,是直接补0.
因此unsigned char c进行整形提升后补码为
00000000 00000000 00000000 11111111 也就是255 。
再看一道题吧!
#include int main(){ char a = -128; printf("%u\n",a); return 0; }
这道题我就不说了,留给评论区的小伙伴解答!
大小端字节序
在内存中,一个字节就是一个地址单元,换句话说就是一个地址管理一个字节
那么问题就来了,一个多字节的数据在内存中是低位在低地址,高位在高地址,亦或是相反。
如9 在内存中是 00000000 00000000 00000000 00001001
还是 00001001 00000000 00000000 00000000
于是就有了大小端字节序之分。
大端就是数据低位在高地址,高位在低地址。
如9 大端存储就是 00000000 00000000 00000000 00001001
小端反之,数据低位在低地址,高位再高地址。
如9 小端存储就是 00001001 00000000 00000000 00000000
大小端取决于处理器,有些处理器还可以
由硬件来选择是大端模式还是小端。
看下图就是小端字节序(查看内存窗口显示的是十六进制)
我们也可以自己打代码看看编译器是大端还是小端
#include int check_sys(){ int i = 1; return (*(char *)&i);//强制类型转换, //char类型的指针只访问一个地址,也就是只拿一个字节}int main(){ int ret = check_sys(); if(ret == 1) { printf("小端\n"); } else { printf("大端\n"); } return 0; }
浮点数在内存中的储存
根据国际标准IEEE(电气和电子工程协会) 754,任意一个二进制浮点数V可以表示成下面的形式:
(-1)^S * M * 2^E
(-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。
M表示有效数字,大于等于1,小于2。
2^E表示指数位。
如9.0 二进制 1001.0->1.001*2^3
对于32位的浮点数,第一位表示符号数S,接着八位表示指数E,剩下表示有效数字M
由于有效数字M大于等于1,小于2,所以有效数字只保存二进制浮点数小数点后的数字
如9.0 二进制 1001.0->1.001*2^3
由于9.0为正数,所以符号位S为0,指数为3,有效数字为M为001 。
因为我们知道指数也可为负数,,所以IEEE 754规定,
存入内存时E的真实值必须再加上一个中间数,中间数为127,
即指数E保存时应为实际指数+127,如9.0 在内存中的指数E为3+127 。
综上我们可得到浮点数9.0在内存中的存储
0 10000010 001 0000 0000 0000 0000 0000
S E M
需要注意的有两项
1.当E全为0时,实际指数为E-127,此时该浮点数非常小,因此有效数字M不再补上1,即为1.M
而是0.M,因为一个数的-127次方很接近0了。
2.当E全为1时,实际指数非常大,所以若符号数S为0,该数表示+无穷大;
若符号数S为1,该数表示-无穷大。