首页 > 作文

C语言中数据在内存如何存储

更新时间:2023-04-04 01:37:57 阅读: 评论:0

目录
数据类型类型的基本归类整形浮点型构造类型(自定义类型)指针类型空类型整形在内存中的存储大小端字节序储存时数据发生截断以及整型提升浮点型在内存中的存储浮点型和整形在内存中的储存方式不同拿出这些储存的数据(三种情乱)情况一:e不全为0或不为全1情况二:e全为0情况三:e为全1

数据类型

常见的数据类型

常见的数据类型字节char字符数据类型1short短整型2int整形4long长整型4long long更长的整形8float浮点型4double双精度浮点型8

注意:

c语言里面没有字符串类型关于int和long的大小:c语言只是规定了:sizeof(long)>=sizeof(int)布尔类型(_bool)(c99引入)专门用来表示真假,但是在c语言中不需要布尔类型也可以表示真假
#include<stdbool.h>int main(){    _bool flag = fal;    _bool flag2 = true;    if(flag)    {        printf("haha\n");}    if(flag2)    {        printf("hehe\n");}return 0;}//只打印了hehe

类型的基本归类

整形

char也属于整形(每一个字符在储存的时候是储存他所对应的ascll值,ascll是整数)

charunsigned charsigned charshortunsigned shortsigned shortintunsigned intsigned intlongunsigned longsigned long

有符号数和无符号数

有符号数

int main(){int a = 10;    int a = -10;return 0;}//a是一个有符号数,它可以储存正负整数//int ===> signed int//short ===> signed short//long ===> signed long

无符号数

有一些变量只有正数由意义,例如年龄,价格。定义这些变量的时候就可以用无符号数定义 ,无符号数只能存储正数。

int main(){    unsigned int a = 10;    //无符号变量只能储存正数    a = -10;    //即使这里输入了一个负数,它也会把这个负数转化成一个正数(不是简单的去掉符号,这是关于二进制的计算)    return 0;}

是否char 等于signed char呢?

答案:取决于编译器

我们会发现这样一件事:
int 就是 signed int
short 就是 signed short
long 就是 signed longchar 等于signed char还是unsigned char 取决于编译器,不同的编译器可能是不同的结果,常见的编译器下是等于signed char

对于有符号数字和无符号数字的打印

打印无符号数应该用%u

%u和%d打印的解读方式不同:

使用%d 时,会认为这是一个有符号数,打印的时候会认为二进制中第一位是符号位;使用%u时,会认为这是一个无符号数据,会认为整个二进制序列都是有效位。
#include<stdio.h>int main(){    unsigned int a = 10;    printf("%u",a);//正确的形式        //如果存储了一个-10进去会怎么样    a = -10;    printf("%u",a);    //会打印4294967286,而这个数据不是随机数    return 0;}

为什么无符号整形储存 -10 的时候会打印出来4284967286(并不是随机数)?

%u单雄信是怎么死的在解读的时候认为此时a仍然存储的是正数,解读了a的补码。在本章后面介绍原反补吗的时候在详细解释细节。

浮点型

浮点型大小float4double8

构造类型(自定义类型)

构造类型数组数组名去掉后剩下的就是数组的类型结构体struct枚举类型enum联合(联合体)类型union

指针类型

指针类型char* pcint * pifloat* pfvoid* pv

空类型

void表示空类型(无类型)

通常应用于函数的返回类型,函数的参数,指针类型

整形在内存中的存储

int a = 10;int b = -10;

然后我们观察a、b在内存中的储存

数据在内存里面是以二进制储存的,但是编译器是以十六进制展现给我们看的:

a在内存中的值是 :0a 00 00 00

b在内存中的值是: f6 ff ff ff

为什么是这样的值呢?下面介绍整数的原码、反码、补码。

原码,反码,补码

整数二进制有3种表示形式,而内存中存储的是二进制的补码

例如 1 的原码:

00000000 00000000 0000万户萧疏鬼唱歌0000 00000001

正整数

正整数的原码、反码和补码相同

负整数

原码:按照一个数的正负直接写出来的二进制就是原码反码:符号位不变,其他位按位取反 (并不是按位取反)补码:反码的二进制序列加1

从原码转换成补码:先取反再加一。

从补码转换成原码:可以先减一再取反,也可以先取反再加一(和原码转换成补码的过程相同)。

类型数据:15数据:-15原码00000000 00000000 00000000 0000111110000000 00000000 00000000 00001111反码00000000 00000000 00000000 0000111111111111 11111111 11111111 11110000补码00000000 00000000 00000000 0000111111111111 11111111 11111111 11110001

解释为什么%u打印-10;会出现4294967286

用上面的方法我们就可以计算出-10的补码:

数据补码1011111111 11111111 11111111 11110110

回到最开始使用%u打印-10会打印成4294967286,是因为在使用%u的时候,不会解读符号位,会将整个32位二进制都当作有效位,读出一个数据,而这个数据就是4294967286。

同时回到刚才a,b的值

int main(){int a = 10;int b = -10;    //a: 00000000 00000000 00000000 00001010    //b: 11111111 11111111 11111111 11110110}//四个二进制位转换成一个十六进制位//a: 00 00 00 0a//b: ff ff ff f6

为什么和在内存界面看到的不同呢?

内存界面和我们计算出来的顺序是相反的:

数据计算结果内存1000 00 00 0a0a 00 00 00-10ff ff ff f6f6 ff ff ff

为什么会倒着存进去?

这就和字节序有关,下面我们来了解字节序

大小端字节序

当储存的内容超过一个字节的时候,储存的时候就有顺序

(一个char类型的数据是没有字节序。char类型的数据只有一个字节,没有顺序)

机器有两种对字节的存储顺序:

大端字节序存储:
低字节数据存放在高地址处,高字节数据存放在低地址处小端字节序存储
低字节数据存放在低地址处,高字节数据存放在高地址处

我们用下面这个例子来解释:

int main(){    int a = 0x11223344;//0x开头说明是十六进制数字    //再内存界面看到:44 33 22 11       return 0;}

而我在观察内存的时候发现我的机器是按照方式2进行存储的,所以我的机器是采用的小端字节序。

那么有什么方法可以快速判断自己当前使用的机器属于哪一种字节序呢?

设计一个小程序判断当前机器属于哪种字节序

#include<stdio.h>int main(){    int a = 1;    //a的十六进制是 00 00 00 01    //如果是大端那么内存中为:00 00 00 01    //如果是小端那么内存中为:01 00 00 00    //只需要判断第一个字节的内容是不是1    char*pc = (char*)&a;    //强制类型转换截取了a的第一个字节    if(*pc)//也炫舞印象图案可以是:if(*(char*)&a)    {        printf("小端");}    el    {        printf("大端");}        return 0;}

储存时数据发生截断以及整型提升

例题1

int main(){char a = -1;signed char b = -1;unsigned char c = -1;printf("%d %d %d ",a,b,c);//会打印出-1 -1 255    return 0;}

解释:

第一步:
这里我们将三个相同的整数 -1 分别存进了两种类型的变量,(在我所使用的vs2019编译器下char和signed char等价),而这两种类型又都属于char类型第二步:
char 类型的变量只能储存一个字节(8个比特位)大小的数据,但是 -1 是整形(包含32个比特位),
这里就需要发生数据截断: -1 的二进制补码是11111111 11111111 11111111 11111111
截断:将补码的最后八位赋值给变量a、b、c。第三步:
这里需要将char类型的数据以%d的方式打印,但是%d只能解读整数数据(整数有四个字节),而char类型的三个变量都只有一个字节,所以这里会发生整型提升:
整形提升:对于有符号数据,高位补符号位,对于无符号数据:高位补0数据(变量)整形提升前整形提升后(补码)原码代表的数据a/b1111111111111111 11111111 11111111 11111111-1c1111111100000000 00000000 00000000 11111111255

%d打印的时候会认为这就是要打印数据的补码,按照打印正常整数的形式打印这三个变量

例题2

#include<stdio.h>int main(){        char a = -128;    printf("%u",a);//会打印4294967168    return 0;}

解释:

第一步:
观察数据: -128 是一个整数,二进制有32位 : 但是接受这个数据的变量是一个char类型的变量(只能接受8个比特位)第二步:
数据的截断:数据二进制(补码)截取(a储存的部分)-12811111111 11111111 11111111 1000000010000000

联想:这里如果是a = 128,那么阶段后的值仍然是10000000

第三步:
打印六年级下册英语整数(四个字节),所以这里需要发生整形提升(a是有符号char,高位补符号位)数据(变量)整形提升前整形提升后(补码)a1000000011111111 11111111 11111111 10000000第四步:
%u的形式打印这个变量,因为%u应该打印的是无符号整数,且打印的时候认为整个32位全为有效位,
就会打印出4294967168

浮点型在内存中的存储

常见的浮点数例子字面浮点数3.14159科学计数法的表示形式1e10(1乘以10的10次方)

注意:

在浮点型数据后面加了f是float类型,不加则默认是double类型%f和%lf默认小数点后六位

浮点型和整形在内存中的储存方式不同

我们通过下面这个例题来探究浮点型和整形在内存中的储存方式有什么不同

#include<stdio.h天降大任于>int main(){int n = 9;float* pf = (float*)&n;    //第一组printf("n = %d\n", n);    //打印出:9printf("*pf = %f\n", *pf);//打印出:0.000000//第二组*pf = 9.0;printf("n = %d\n", n);  //打印出:1091567616printf("*pf = %f\n", *pf);//打印出:9.000000return 0;}

为什么会出现这样的情况?

回答这个问题前,先来了解浮点型的二进制存储形式:

国际标准电气电子工程师学会(ieee):任何一个二进制浮点数v都可以表示成下面的形式

表示形式:(-1)^s * m * 2^e(-1)^s表示符号位,当s为0 时表示正数,当s为1时,表示负数m表示有效数字,大于等于1,小于等于22^e表示指数位(5.5)十进制(5.5)二进制5.5101.15.5*(10^1)1.011*(2^2)
十进制浮点数:5.5转化成二进制:101.1可以写成:(-1)^0 * 1.011 * (2^2)s = 0m = 1.011e = 2只需要储存sme三个值
ieee浮点数标准定义了两种基本的格式:以四个字节表示的的单精度格式和八个字节表示的双精度格式

单精度浮点数储存格式(32位)

第一位接着8位剩下23位符号位指数位有效位

双精度浮点数储存格式(64位)

第一位接着11位剩下52位符号位指数位有效位

ieee754对于有效数字m和指数e有一些特别的规定:

关于m:
1.我们已经知道1<=m<2,也即是说m一定可以写成这样的形式:1.xxxxxx
其中xxxxxx表示小数点后面的部分
2.在计算机内部储存m时,由于第一位总是1,所以把这个1省略,只保存后面的小数部分,这样可以节约一位有效数字,这样的话储存的数据精度就可以提升一位:例如在单精度浮点型存储格式中,最后23位作为有效位,但是储存在计算机的数据精度是24位关于e:
计算机会认为这是一个无符号数,但是十几行会存在很多e取负数的情况,所以ieee754规定:存入内存时,e的真实值必须在加上一个中间数 ,对于单精度,这个中间数(也叫做偏移量)是127,对于双精度,这个中间数是1023
例如:对于十进制的数字0.5,它的二进制是0.1,e= -1;那么我们就需要把-1在加上127得到126后,将126储存在指数位

拿出这些储存的数据(三种情乱)

情况一:e不全为0或不为全1

e: 指数位值减去127(1023)得到真实值m: 有效位的数值前面加上1.

情况二:e全为0

e:
真实的e是一个十分小的数字,接近0;
这时候不用计算,e直接就等于1-127(1-1023)就是它的真实值m:
m不再在前面加上1,而是还原成0.xxxxxx的小数,这样做是为了表示正负0,以及接近于0的很小的数字。

情况三:e为全1

真实的e是一个十分大的数字,代表正负无穷大的数字

解释上面的例子

第一组为什么以%f打印整数9,会打印出0.000000?

原因:

此时e为全0,是一个会被判定成一个十分小的数据,所以打印0.000000

为什么第二组中以%d的形式打印*pf时,会打印出1091567616?

本文发布于:2023-04-04 01:37:55,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/e4786876ce8ae0ed0dd0c86d39722f92.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:C语言中数据在内存如何存储.doc

本文 PDF 下载地址:C语言中数据在内存如何存储.pdf

标签:补码   数据   字节   类型
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图