【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


相关文章
|
2月前
|
存储 编译器 C语言
C语言存储类详解
在 C 语言中,存储类定义了变量的生命周期、作用域和可见性。主要包括:`auto`(默认存储类,块级作用域),`register`(建议存储在寄存器中,作用域同 `auto`,不可取地址),`static`(生命周期贯穿整个程序,局部静态变量在函数间保持值,全局静态变量限于本文件),`extern`(声明变量在其他文件中定义,允许跨文件访问)。此外,`typedef` 用于定义新数据类型名称,提升代码可读性。 示例代码展示了不同存储类变量的使用方式,通过两次调用 `function()` 函数,观察静态变量 `b` 的变化。合理选择存储类可以优化程序性能和内存使用。
157 82
|
1月前
|
存储 C语言 C++
深入C语言,发现多样的数据之枚举和联合体
深入C语言,发现多样的数据之枚举和联合体
深入C语言,发现多样的数据之枚举和联合体
|
1月前
|
存储 C语言
深入C语言内存:数据在内存中的存储
深入C语言内存:数据在内存中的存储
|
1月前
|
C语言
回溯入门题,数据所有排列方式(c语言)
回溯入门题,数据所有排列方式(c语言)
|
2月前
|
存储 人工智能 C语言
数据结构基础详解(C语言): 栈的括号匹配(实战)与栈的表达式求值&&特殊矩阵的压缩存储
本文首先介绍了栈的应用之一——括号匹配,利用栈的特性实现左右括号的匹配检测。接着详细描述了南京理工大学的一道编程题,要求判断输入字符串中的括号是否正确匹配,并给出了完整的代码示例。此外,还探讨了栈在表达式求值中的应用,包括中缀、后缀和前缀表达式的转换与计算方法。最后,文章介绍了矩阵的压缩存储技术,涵盖对称矩阵、三角矩阵及稀疏矩阵的不同压缩存储策略,提高存储效率。
390 8
|
1月前
|
存储 C语言
C语言中的浮点数存储:深入探讨
C语言中的浮点数存储:深入探讨
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
34 3
|
8天前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
24 6
|
28天前
|
存储 缓存 C语言
【c语言】简单的算术操作符、输入输出函数
本文介绍了C语言中的算术操作符、赋值操作符、单目操作符以及输入输出函数 `printf` 和 `scanf` 的基本用法。算术操作符包括加、减、乘、除和求余,其中除法和求余运算有特殊规则。赋值操作符用于给变量赋值,并支持复合赋值。单目操作符包括自增自减、正负号和强制类型转换。输入输出函数 `printf` 和 `scanf` 用于格式化输入和输出,支持多种占位符和格式控制。通过示例代码详细解释了这些操作符和函数的使用方法。
35 10
|
21天前
|
存储 算法 程序员
C语言:库函数
C语言的库函数是预定义的函数,用于执行常见的编程任务,如输入输出、字符串处理、数学运算等。使用库函数可以简化编程工作,提高开发效率。C标准库提供了丰富的函数,满足各种需求。