剖析数据在内存中的存储

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

了解了数据在内存中如何存储,如何取用,对我们修改bug很有帮助


提示:以下是本篇文章正文内容,下面案例可供参考

一、数据类型基本归类

1.C语言中给的基本内置类型与归类

(1)整型家族

int----------------------------4个字节

char-------------------------1个字节(内存中以ASCII值存放,所以算是整型家族的1一员)

short------------------------2个字节

long-------------------------4 / 8个字节

long long------------------8个字节

== 注:这些数据类型又分为signed和unsigned两种类型。==

(2)浮点型家族

float

double

== 两种类型的精确度不同,后面会谈到 ==

(3)构造类型

数组类型
结构体类型(struct)
枚举类型(enum)
联合类型(union)

(4)指针类型

int*
char*
float*
void*

(5)空类型

void

二、整型在内存中的存储

int x=10;
int y=20;

类似x,y这样的变量在内存中会开辟四个字节的空间,那么会如何存储呢?

2.1原码,反码,补码

计算机中的整数通过原码,反码,补码存放在内存中。

对于signed类型的数据来说,这三种表示方法通常都有符号位数值位两部分。

符号位是二进制的第一个数字,用1表示正,用0来表示负。

正数的原,反,补都是一样的

负数原码可以直接通过数值翻译
反码将符号位不变,其他位取反得到
补码课通过将反码加一得到

计算机中整型在内存中存储的都是补码

运用补码可以将符号位和数值位进行统一处理,而不需要拆开分别计算

2.2大端存储和小端存储

大端存储就是将数据的低位存放到内存高地址处,数据的高位放在内存的低地址处
小端存储就是将数据的高位存放到内存高地址处,数据的低位放在内存的低地址处

#include<stdio.h>

int main()
{
	int a = 10;
	int b = -10;
	return 0;
}

在这里插入图片描述
a的值是10,转化为十六进制为0x0000000a,如图就是小端的存储模式

那么如何用代码进行大端小端的判断呢

int a = 1来计算
以十六进制存放为0x00000001
大端中00 00 00 01
小端中01 00 00 00
可以通过内存中数据的第一个字节可以判断出是大端还是小端
所以可以通过以下代码来求出

#include<stdio.h>

int main()
{
	int a = 1;
	char b = *((char*)&a);
	printf("%d\n", b);

	return 0;
}

取出a的地址,进行强制类型转化,取出第一个字节内的数值,赋给b,进行打印

2.3练习

(1)

//输出什么?
#include <stdio.h>
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;
}

打印时要进行整型提升
-1作为整型,补码为11111111111111111111111111111111,截断后,变成11111111
通过a,b,c的不同类型来进行判断值的大小

在这里插入图片描述

(2)

#include <stdio.h>
int main()
{
  char a = -128;
  printf("%u\n",a);
  return 0;
}

-128的补码为:11111111111111111111111110000000,截断后10000000
因为a是一个char类型的数据,所以整型提升后为11111111111111111111111110000000
以无符号形式打印出来
在这里插入图片描述

(3)

#include <stdio.h>
int main()
{
  char a = 128;
  printf("%u\n",a);
  return 0;
}

解释过程同(2)

(4)

int main()
{
  char a[1000];
  int i;
  for(i=0; i<1000; i++)
 {
    a[i] = -1-i;
 }
  printf("%d",strlen(a));
  return 0;
}

strlen这个函数会从给出的地址往后读,直到遇到‘\0’,那么当a[i]=='\0’时,就停止
在这里插入图片描述
如图所示,a[i]的数值会随着圈的逆时针变化
在这里插入图片描述

(5)

#include <stdio.h>
unsigned char i = 0;
int main()
{
  for(i = 0;i<=255;i++)
 {
    printf("hello world\n");
 }
  return 0;
}

unsiged char类型最大值就是128,所以会打印死循环

三:浮点数在内存中的存储

3.1浮点数在内存中的存储规则

任一个二进制浮点数在内存中存储的形式为

V=(-1)^S* M *2 ^E
(-1)^S表示符号位,当S=0,V为正数;当S=1,V为负数。
M表示有效数字,大于等于1,小于2。
2^E表示指数位。

就比如5.0,二进制为101.0==>(-1)^0 * 1.010* 2^2

对于一个32位的平台来说:
在这里插入图片描述

对于一个64位平台来说:
在这里插入图片描述

== 注:对于有效数字M,由于它的大小为1~2,所以系统默认将第一位的1舍去不存,在使用时加上(如1.001在存储时只放001)。
对于无符号E来说,可能存在负数的情况,所以我们就在存储时给它加上一个中间数。32位平台加127,64位平台加1023

3.2练习

下面给一道例题解释

int main()
{
int n = 9;
float *pFloat = (float *)&n;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
*pFloat = 9.0;
printf("num的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
return 0;
}

在这里插入图片描述

n的十六进制表示为0x00 00 00 09
转化为二进制为0 00000000 00000000000000000001001
这里的指数位置全为0,我们上面有介绍到,指数位置需要加一个中间数127,所以原本的指数是很小的,所以以浮点数打印出来是很小的,直接为0
再以浮点数9.0,来存放进去,二进制形式为1001.0==>(-1) ^ 01.00102^3
所以放进去为01000001000100000000000000000000
再把这个二进制换成整数,就是结果

总结

数据在内存中如何存储,有助于我们深度了解bug的成因,这也是我的第一次写博客,有什么不对的地方欢迎指出。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值