> 文档中心 > 深入了解c语言数据类型在内存中的储存

深入了解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,该数表示-无穷大。