【C语言】整形数据的存储和读取过程

简介: 整形数据的存储和读取过程

一. 问题引入

观察下面一段代码:


#include <iostream>
using namespace std;
int main()
{
  unsigned int a = -10;
  printf("%d\n", a);// -10
  printf("%u\n", a);// 4294967286
  return 0;
}


最终程序编译运行通过,没有任何的报错或警告。按理来说 -10 是不能被存入一个无符号类型的变量里的,我们可以说C语言对类型的检查不严格,那么这个 -10 究竟是怎么被存进去的呢?


二. 存储过程

存储的过程可以分为以下三步:


看变量的类型,决定开多大的空间

把要存入的数值转化成二进制补码形式

把转化好的二进制补码按大小端规则存入到先前开辟好的空间当中(注意是以字节为单位把数据存入到空间当中)

具体回到上面的例子,看看 -10 是怎么被存到 a 这个变量里去的。


第一步:首先操作系统看到 a 这个变量的类型是 int,所以会为其在栈中开辟出 4 字节的空间。注意开空间的时候不会考虑这个变量到底是有符号还是无符号,操作系统只关心到底要开出多少的空间。

bfd1df26dda142248e0198664aeef9a5.png



第二步:空间有了之后,就要把数据放入到空间中,需要放入的数据是 -10,不论是正数还是负数,我们都要把它转化成补码,之后才能存入到空间中。

b162e81c990b431fa2d91416bdf54903.png


第三步:最后一步把数据放入空间时要考虑大小端的问题,现在的电脑大部分都是小端存储,即低权值数据存到高地址,高权值数据存到低地址。


PS:大小端存储方案的本质是数据和空间按照字节为单位的一种映射关系


9bd80488143d450188404a854d8e453a.png


我们在程序中打开内存串口,可以看到 a 的数据存放确实是按照小端来存的

26757fa7f9d840beacda636d57227f88.png


三. 读取过程

读取过程分为以下两步:


按照大小端规则,以字节为单位拿出空间中的二进制补码数据

根据变量的类型,去解释拿出来的二进制补码数据

无符号类型:补码 = 源码

有符号类型:

最高位为0说明是正数,此时补码 = 源码

最高位为1说明是负数,需要把补码转化成源码

第一步:根据小端方案把数据从空间中逐个字节地拿出来

370168579c0748f988f360b375d0cf04.png



第二步:根据变量类型解释从空间中取出来的二进制补码序列

c4953359f64a4d90b396d4d505eaa13b.png


四. 分析一段小代码

int main()
{
  int i = -20;
  unsigned int j = 10;
  printf("%d\n", i + j);
  return 0;
}


首先不管 i 和 j 是有符号还是无符号,只需把数据都当做有符号数转化成二进制补码存入到开好的4个字节的空间中即可:


c0f710df74a849aaaba27b9151106745.png


然后 printf 里要打印 i+j 表达式的值,我们把它们的二进制补码直接相加。


最后是以%d格式输出,即按照有符号整形格式输出,此时因为二进制补码中最高位为1表示负数,所以要把源码转化成补码才能输出最终结果 -10

1ac47294f7514a06ba25d0189c6c5875.png


相关文章
|
11月前
|
存储 程序员 编译器
C 语言中的数据类型转换:连接不同数据世界的桥梁
C语言中的数据类型转换是程序设计中不可或缺的一部分,它如同连接不同数据世界的桥梁,使得不同类型的变量之间能够互相传递和转换,确保了程序的灵活性与兼容性。通过强制类型转换或自动类型转换,C语言允许开发者在保证数据完整性的前提下,实现复杂的数据处理逻辑。
|
存储 编译器 数据处理
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
392 12
|
11月前
|
存储 数据管理 C语言
C 语言中的文件操作:数据持久化的关键桥梁
C语言中的文件操作是实现数据持久化的重要手段,通过 fopen、fclose、fread、fwrite 等函数,可以实现对文件的创建、读写和关闭,构建程序与外部数据存储之间的桥梁。
|
存储 数据建模 程序员
C 语言结构体 —— 数据封装的利器
C语言结构体是一种用户自定义的数据类型,用于将不同类型的数据组合在一起,形成一个整体。它支持数据封装,便于管理和传递复杂数据,是程序设计中的重要工具。
|
存储 C语言 C++
深入C语言,发现多样的数据之枚举和联合体
深入C语言,发现多样的数据之枚举和联合体
140 0
深入C语言,发现多样的数据之枚举和联合体
|
存储 C语言
深入C语言内存:数据在内存中的存储
深入C语言内存:数据在内存中的存储
195 0
|
2月前
|
存储 C语言
`scanf`是C语言中用于按格式读取标准输入的函数
`scanf`是C语言中用于按格式读取标准输入的函数,通过格式字符串解析输入并存入指定变量。需注意输入格式严格匹配,并建议检查返回值以确保读取成功,提升程序健壮性。
974 0
|
4月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
313 15
|
10月前
|
存储 算法 C语言
【C语言程序设计——函数】素数判定(头歌实践教学平台习题)【合集】
本内容介绍了编写一个判断素数的子函数的任务,涵盖循环控制与跳转语句、算术运算符(%)、以及素数的概念。任务要求在主函数中输入整数并输出是否为素数的信息。相关知识包括 `for` 和 `while` 循环、`break` 和 `continue` 语句、取余运算符 `%` 的使用及素数定义、分布规律和应用场景。编程要求根据提示补充代码,测试说明提供了输入输出示例,最后给出通关代码和测试结果。 任务核心:编写判断素数的子函数并在主函数中调用,涉及循环结构和条件判断。
573 23
|
9月前
|
人工智能 Java 程序员
一文彻底搞清楚C语言的函数
本文介绍C语言函数:函数是程序模块化的工具,由函数头和函数体组成,涵盖定义、调用、参数传递及声明等内容。值传递确保实参不受影响,函数声明增强代码可读性。君志所向,一往无前!
363 1
一文彻底搞清楚C语言的函数