【C语言】整型数据在内存中的存储(详解)

#数据存储

数据类型

我们知道,C语言中有很多不同的数据类型

在cppreference.com网站上可以找到C语言中的不同类型【链接】

image-20211203210814743

先来认识一个不那么常见的类型

布尔类型

C99中引入了布尔类型 _Bool
实质:把1和0变成ture和false

#include<stdbool.h>

int main()
{
	_Bool flag = true;
	if(flag)
	{
		printf("hehe\n");
	}
	return 0;
}

代码的效果如下:

image-20211203215617481

因为布尔类型和以1-0来判断正误的作用是相同的

所以这个类型我们一般不会使用


无符号数据的打印

Unsigned无符号数用%u打印

image-20211203215943720

  • 用%d打印的时候,认为是有符号数
  • 用%u打印无符号数的时候,负数会乱码

我们知道,整型数据在内存中占用4个字节(32位),double类型是8个字节

不同数据占用的字节

image-20220110103140009

在之前的学习中,我们已经知道了如何使用这些不同的数据类型

但是你知道,数据在内存中是怎么存储的吗?

这篇博客将带你认识整型在内存中的存储


整型在内存中的存储

先来认识一下整型家族都有谁吧!

整型家族

  • char

    ​ unsigned char

    ​ signed char

  • short

    ​ unsigned short [int]

    ​ signed short [int]

  • int

    ​ unsigned int

    ​ signed int

  • long

    ​ unsigned long [int]

    ​ signed long [int]

我们平时用的最频繁的int其实是signed int

char到底是signed char还是unsigned char,取决于编译器的实现

常见的编译器下,char就是signed char

在知道整型在内存中的存储方式之前

我们需要先认识一下三个好朋友**“原 反 补”**

“原反补”三兄弟

正整数:原反补码相同

负整数:

原码按照一个数的正负直接写出来的二进制
反码符号位不变,其他位按位取反
补码反码的二进制序列+1,得到补码

二进制要怎么写出来呢?

下面以15为例(前面省略了24位)

每一个1都是2的权重

image-20211203221012177

这就是二进制和十进制转换的方式

而15作为正数,原反补码都是这个二进制数

00000000 00000000 00000000 00001111

正数的原反补码相同


什么是符号位?

每一个整型都有4个字节,由32个bit位组成

其中原码的第一位,就是该二进制的符号位

正数为0,负数为1

最高位为符号位,后面的是有效位

再举个-15的例子

10000000 00000000 00000000 00001111原码
11111111 11111111 11111111 11110000反码
11111111 11111111 11111111 11110001补码

为了进一步了解数据在内存中的存储方式,我们将15的补码转化为十六进制

每4个二进制比特位对应一个十六进制数,转换结果如下

00000000000000000000000000001111
0000000F

image-20211203222426049

可当我们在VS编译器-监视-内存窗口里面查看15数据的时候

展示的是以下的16进制形式

image-20211203222141783

可以看到,内存中存储的十六进制,和我们计算出来的是反着的

这又是为什么呢?


大小端问题

大端字节序存储:

​ 当一个数据的低字节的数据存放在高地址处,高字节序的内容放在了低地址处,这种存储方式就是大端字节序存储

小端字节序存储:

​ 当一个数据的低字节数据存放在低地址处,高字节序的内容放在了高地址处,这种存储方式就是小端字节序存储

简称:小同大异

而我们图中VS内存窗口显示的这种“反着放”的方式,是因为:

  • VS编译器下,内存窗口显示的是左低右高
  • 二进制码是00000000 00000000 00000000 00001111

所以VS编译器是小端存储

image-20211203225659881

而如果是以00 00 00 0f的方式放入内存,则是大端字节序存储


负数示例

int b=-10
原码10000000000000000000000000001010
反码1111111111111111111111111110101
补码11111111111111111111111111110110
f ff ff ff 6

image-20211203230349186

了解了大小端的机制之后,我们可以来写一个简单的函数

判断当前编译器是大端还是小端

image-20211203231627550

#include <stdio.h>
int check_sys()
{
	int a=1;
	char*p=(char*)&a;
	if(1==*p)
		return 1;
	else
		return 0;		
}

int main()
{
	int b=check_sys(); 
	if(1==b)
		printf("小端\n");
	else
		printf("大端\n");
    
	return 0;
 } 

这串代码的自定义函数部分可以进行优化

因为*p=1时返回1

其他情况返回0

所以可以选择直接返回*p

//代码优化2 
int check_sys()
{
	int a=1;
	char*p=(char*)&a;
	return *p;	
}

进一步优化,我们可以把(char*)&a直接进行解引用并返回他的值

这样就能跳过中间变量p

//代码优化3
int check_sys()
{
	int a=1;
	return *(char*)&a;	
}

这里有两个问题需要注意:

不能直接对a进行强制类型转换,这种方式是错的

大小端是把数据放在内存之后才有的现象

大小端讲的是以字节为单位的顺序

char类型只有一个字节,没有大小端问题


为什么整型在内存中存放的是补码呢?

在计算机系统中,数值一般用补码来表示和存储,原因在于,试用补码,可以将符号位和数值域统一处理;

同时,加法和减法也可以统一处理(CPU只有加法器)

此外,补码与反码相互转换,其运算过程是相同的,不需要额外的硬件电路。

计算机中只有加法器,减法用加法来模拟

1-1→1+(-1)

如果用原码的计算:

00000000 00000000 0000000 00000001+
10000000 00000000 0000000 00000001=
10000000 00000000 0000000 00000010-2 错误

补码:

00000000 00000000 0000000 000000011原
10000000 00000000 0000000 00000001-1原

它们的补码

00000000 00000000 00000000 00000001 +1的补码
11111111 11111111 1111111 11111111 =-1的补码
00000000 00000000 0000000 00000000结果为0

其中第一个1为符号位


结语

到这里,整型在内存中存储的基本知识就已经讲完啦

如果对你有帮助,还请不要吝啬手里的赞👍!

能留下个评论就更好了

这对我真的很重要!!!

  • 26
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论
C语言的指针函数是指返回值为指针类的函数,它们在函数的定义和调用上与普通函数有所不同。 指针函数的定义需要在函数名前加上返回类为指针的声明,并在函数体内返回一个指针类的值。例如,我们可以定义一个返回整指针的函数如下: ```c int* allocateIntArray(int size) { int* array = (int*)malloc(size * sizeof(int)); return array; } ``` 在调用指针函数时,需要用一个与返回类相匹配的指针变量接收返回值。例如,调用上述函数并将返回值存储在指针变量: ```c int* myArray = allocateIntArray(5); ``` 上述代码,myArray是一个整指针变量,它用于存储allocateIntArray函数的返回值。这个返回值是一个指向分配的整数组的指针。 指针函数的调用过程,我们还需要注意以下几点: 1. 为了避免内存泄漏,我们通常需要在不使用指针的时候手动释放内存,可以使用free函数来释放通过malloc分配的内存。 2. 在函数内部分配的内存空间返回给调用者后,我们应该确保在使用这块内存之前不会被其他操作修改或释放掉,否则可能导致程序运行时错误。 3. 指针函数也可以作为参数传递给其他函数,使得我们可以更方便地使用和操作指针类数据。 总结来说,指针函数是具有返回值为指针类的函数,其定义和调用方式与普通函数有所区别。使用指针函数可以更灵活地操作和传递指针类数据,但在使用时需要注意内存的释放和确保指针的有效性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕雪华年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值