整数在内存中原来是这样存储的,看完表示头好痒,感觉要长脑子了!

news2025/1/11 21:46:39

本篇文章来介绍一下整形在内存中的存储,内容丰富,干货慢慢。

目录

1.整形家族

2.整形在内存中的存储

3.大端小端存储

4.练习

1.整形家族

在开始之前,我们先来简单回顾一下整形家族:

char

        unsigned char

        signed char

short

        unsigned short

        signed short

int 

        unsigned int 

        signed short

long 

        unsigned long

        signed long

long long 

        unsigned long long

        signed long long

看到这里,我想肯定会有小伙伴问为什么 char 也属于整形家族,嘿嘿,那是因为 char 类型在内中存储的其实是字符对应的ASCII值,ASCII值也是整数,所以字符类型也归类到整形家族。

对于 unsigned (无符号)和 signed (有符号):生活中有些数值是有正值和负值,如温度,我们要用有符号类型来存储,我们在使用有符号类型时,signed 是可以省略不写的,例如 int 等同于 singed int ,但是要使用无符号类型时,unsigned 是不可以省略的,例如 unsigned int 。

这里值得注意的是,对于 char 类型来说:只写 char 到底是 unsigned char 还是 signed char C语言是没有明确规定的,只是有些编译器做了规定,如在VS编译器上,char 就等同于 signed char 。

2.整形在内存中的存储

变量的创建是要在内存中开辟空间的,空间的大小是根据不同的类型而决定的。

下来了解下面的概念∶

原码、反码、补码:

计算机中的整数有三种表示方法,即原码、反码和补码。

三种表示方法均有符号位数值位两部分,符号位都是用0表示“正”用1表示"负”,而数值位三种表示方法各不相同。

原码:

直接将二进制按照正负数的形式翻译成二进制就可以。符号位是二进制的第一位。

反码:

将原码的符号位不变,其他位依次按位取反就可以得到了。

补码:

反码加一就得到补码

正数的原、反、补码都相同。

对于整形来说:数据存放内存中其实存放的是补码。为什么呢?

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。这里不理解可以先往下看。

看下面一段代码:

在有符号类型中,二级制表示形式的第一位是符号位,后面位是数值位。

int main()
{
	int num = 10;//创建一个整型变量,叫num,这时num向内存申请4个字节来存放数据
	//整形4个字节 - 32个bit位(二进制位)   正整数原码,反码,补码相同
	//00000000000000000000000000001010 - 原码
	//00000000000000000000000000001010 - 反码
	//00000000000000000000000000001010 - 补码
	//0x 00 00 00 0a  16进制   a是10

	int num2 = -10;
	//10000000000000000000000000001010 - 原码
	//11111111111111111111111111110101 - 反码
	//11111111111111111111111111110110 - 补码
	//0x FF FF FF F6  //16进制
	return 0;
}

我们可以通过调试,来查看内存中的数据,通过&num来得到num的地址,不知道如何调试的可以看我上篇关于如何调试的文章。 0x是表示后面的数是16进制数。

本质上内存中存放的是二进制,但VS为了方便显示,显示的是16进制,一个16进制位等于4个二进制位,因为16等于2的4次方。并且还可以发现数据在内存中是倒着存放的,关于为什么后面会讲。

 可以发现-10在内存中存放的是一个很大的数,也就是-10的补码。其实对于正整数来说,存放的也是它的补码,只不过是补码,反码,原码相同。

内存中的计算也是通过补码计算的:

上面说到计算机只有加法器,所以当我们计算减法时,是先将被减数换成负数再相加。

下面举一个例子计算1-1,换成加法就是1+(-1)

我们可以先用原码计算一下

00000000000000000000000000000001    1的原码
10000000000000000000000000000001   -1的原码

相加,符号位也相加,得到:
10000000000000000000000000000010    -2

可以发现原码相加的得到是-2,是错误的。下面用补码计算

00000000000000000000000000000001 1的补码

10000000000000000000000000000001   -1的原码  我们把它转换为补码

1111111111111111111111111111111111110   -1的反码  (符号位不变,其他位按位取反)
1111111111111111111111111111111111111   -1的补码  (反码加一)

将1的补码与-1的补码相加得到:
100000000000000000000000000000000  变成33位 要去掉最高位

00000000000000000000000000000000    0  得到0

关于从补码得到原码,有两种方式:

1.通过 原码符号位不变,其他位取反得到反码,反码+1得到补码 这种方式反着推

2.补码 符号位不变,其他位取反,再+1就可得到原码,可以发现与原码得到补码得方式相同,想不到吧,这就是计算机发明者的智慧。

原码,反码,补码之间关系如下图所示: 

 这里就可以理解为什么补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路了。

3.大端小端存储

什么是大端小端∶

又称大端小端字节序,是以字节为单位,讨论存储顺序的,8个比特位(二进制位)或两个16进制是一个字节

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;

小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地址中。为什么有大端和小端∶

为什么会有大小端模式之分呢?

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为8bit。但是在C语言中除了8bit的char之外,还有16bit的short型,32bit的long型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如果将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。

例如一个16bitshort类型x变量,在内存中的地址0x0010x的值为0x1122,那么0x11为数据的高位,0x22为数据的地位。对于大端模式,就将0x11放在低地址中,即0x0010中,0x22放在高地址中,即0x0011中。小端模式,刚好相反。大端小端存储是由自己电脑的硬件来决定的。

百度2015年系统工程师笔试题︰

请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。(10分)
 

#include<stdio.h>
int main()
{
	int a = 1;
	char b = *(char*)&a;//&a 是int *类型。
	if (b == 1)
	{
		printf("小端字节序存储\n");
	}
	if (b == 0)
	{
		printf("大端字节序存储\n");
	}
	//printf("%d", b);
	return 0;
}

 

4.练习

这里一起做做些练习,看看自己掌握的怎么样,顺便再讲一些干货。

1. 

#include<stdio.h>

int main()
{
	char a = -1;
	//-1是整数发生截断
	//11111111111111111111111111111111 -1补码
	//11111111 a截断
	signed char b = -1;
	//与a相同
	unsigned char c = -1;
	//11111111111111111111111111111111 -1补码
	//11111111  c截断

	//%d 十进制打印有符号整形数据,发生整型提升
	//整型提升时有符号高位补符号位,无符号补0
	//a 11111111111111111111111111111111补码
	//  11111111111111111111111111111110 反码
	//  10000000000000000000000000000001  -1 原码打印
	//b 和a相同
	//c 111111111  无符号高位补0
	//  00000000000000000000000011111111 255
	printf("a=%d b=%d c=%d", a, b, c);  -1 -1 255
	return 0;
}

2.

#include<stdio.h>

int main()
{
	char a = -128;
	//-128
	//10000000000000000000000000001000000  -128原码
	//11111111111111111111111111110111111   反码
	//11111111111111111111111111111000000   补码
	//10000000//截断
    //打印整形提升
	//11111111111111111111111111111000000
	//补码按%u无符号打印  认为是无符号数,原反补相同,打印一个很大的数
	printf("%u\n", a);
	return 0;
}

3.  与第2道结果相同

#include<stdio.h>

int main()
{
	char a = 128;
    //截断后是与-128截断后相同
    //所以结果也与-128相同
	printf("%u\n", a);
	return 0;
}

4.

#include<stdio.h>
int main()
{
	int i = -20;
	unsigned int j = 10;
	printf("%d\n", i + j);
	return 0;
}

写到这里是不是有些不敢写-10了,没关系我们来推理一下

10000000000000000000000000010100  -20原码
111111111111111111111111111111101011  -20反码
111111111111111111111111111111101100  -20补码


00000000000000000000000000001010  10补码 与原码相同 与signed int 相同


111111111111111111111111111111110110  i + j  是补码
10000000000000000000000000001001       反码
10000000000000000000000000001010  -10   原码

5.

#include<stdio.h>
#include<Windows.h>
int main()
{
	unsigned int i;//i恒大于0
	for (i = 9; i >= 0; i--)//会死循环 打印很大的数
	{
		printf("%u\n", i);
	}
	return 0;
}

那 i==0 后再 -1 是谁呢。 我们可以看一下 char 类型, -128到127

 可以发现开始了循环,同理,当类型位为 unsigned char 时,最大值为255,在加一就是0。

知道了这一点,我们来做一下最后一道题

6.

#include<stdio.h>

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

strlen是求的是 '\0' 之前的字符个数,而'\0'的ASCII码值是0,所以这里计算的是0之前的数组元素个数。

我们可以看 a 数组中的内容 -1,-2,-3 .... -127,-128,因为是char类型的数组,根据上面图片,所以后面是127,126,125 ...2,1,0,-1,... 之后再循环,我们统计 0 之前的元素个数,有128+127=255个,所以答案是255。

本篇结束,下篇讲浮点型数据在内存中的存储

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/580341.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

chatgpt赋能python:Python补0——让你的数字更规整

Python 补0——让你的数字更规整 在编写代码的过程中&#xff0c;我们经常需要将数字格式化&#xff0c;以便更好地呈现给用户。例如&#xff0c;一个价格可能需要显示为“$100.00”而不是“$100”或“$100.0”。这时候&#xff0c;我们就需要使用 Python 的补0功能。本文将为…

【015】C++的函数详解

C的函数详解 引言一、函数介绍1.1、函数的概述1.2、函数的分类 二、函数定义、声明、调用等2.1、定义函数2.2、函数声明2.3、调用函数2.4、默认参数2.5、函数重载2.6、函数的调用过程 三、函数的传参3.1、普通变量作为函数的参数3.2、数组作为函数的参数 总结 引言 &#x1f4a…

浅浅入门SpringCloud

Spring Cloud是一系列框架的有序集合。它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发&#xff0c;如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等&#xff0c;都可以用Spring Boot的开发风格做到一键启动和部署。Spring Cloud并没有…

如何在Linux机器中测试存储/磁盘I/O性能?

在Linux环境中&#xff0c;了解存储/磁盘I/O性能对于评估系统性能和优化存储子系统非常重要。通过测试存储/磁盘I/O性能&#xff0c;我们可以确定磁盘的读写速度、延迟和吞吐量等指标。本文将介绍几种常用的方法来测试Linux机器中的存储/磁盘I/O性能。 方法一&#xff1a;使用d…

测试开发工程师必问面试题

1.对测试开发的理解 测试开发首先离不开测试&#xff0c;而软件测试是指&#xff0c;在规定的条件下对程序进行操作&#xff0c;以发现程序错误&#xff0c;衡量软件质量&#xff0c;并对其是否能满足设计要求进行评估的过程。 而且&#xff0c;现在不仅仅是通过手工测试来发…

【C++】容器篇(四)—— queue的基本介绍以及模拟实现

前言&#xff1a; 在上期博文中我带大家对stack进行深入的学习&#xff0c;本期我将带领学习的是关于 queue的基本知识&#xff0c;并且还将给大家介绍并实现 priority_queue。接下来&#xff0c;让我们正式本期的内容。 目录 &#xff08;一&#xff09;queue的基本介绍 &…

83.响应式设计原则

什么是响应式设计&#xff1f; ● 使网页根据任何可能的屏幕尺寸&#xff08;窗口或视口尺寸&#xff09;调整其布局和视觉风格的设计技术。 ● 在实践中&#xff0c;这意味着响应式设计使网站可以在所有设备上使用&#xff0c;如台式电脑、平板电脑和手机。 ● 这是一套做法&…

window安装docker Desktop和wsl2

目录 一、先到微软商店下载terminal (也就是power shell,后续命令都在这个里面执行) 二、安装docker Destop 1.打开控制面板 2.勾选Hyper-V服务 3、根据提示重启电脑&#xff0c;等待更新即可 二.启动Docker Desktop 2.1 报错&#xff0c;提示需要最新的WSL 方式一&#…

阿里云服务器CPU内存怎么选?几核几G合适?

阿里云服务器配置怎么选择&#xff1f;CPU内存、公网带宽和系统盘怎么选择&#xff1f;个人用户选择轻量应用服务器或ECS通用算力型u1云服务器&#xff0c;企业用户选择ECS计算型c7、通用型g7云服务器&#xff0c;阿里云服务器网分享阿里云服务器配置选择方法&#xff1a; 目录…

Day4 计算糖果、进制转换

✨个人主页&#xff1a; 北 海 &#x1f389;所属专栏&#xff1a; C/C相关题解 &#x1f383;操作环境&#xff1a; Visual Studio 2019 版本 16.11.17 文章目录 选择题1、C函数 编程题1、计算糖果2、进制转换 选择题 1、C函数 题目&#xff1a;下列程序执行后,输出的结果为…

maven依赖选择策略(依赖调解)

这里先抛出结论 最短路径原则: 不同级依赖, 选择路径最短&#xff08;对于传递性依赖和一级依赖&#xff09;声明优先原则 : 同级依赖,先声明的覆盖后声明的&#xff08;对于传递性依赖&#xff09;同级依赖后加载覆盖先加载原则&#xff08;不属于传递性依赖的情况&#xff0…

Collections提供的同步包装方法

Java同步容器类是通过synchronized&#xff08;内置锁&#xff09;来实现同步的容器&#xff0c;比如Vector、 HashTable以及SynchronizedList等容器。 线程安全的同步容器类主要有&#xff1a; Vector、 Stack、 HashTable等。 Collections提供的同步包装方法 Java提供一组包…

VTK Java项目构建和运行

date: 2019-04-02 10:24:00 VTK Java项目构建和运行 准备工作 本文的运行环境是Ubuntu。在自己建立的VTK build的文件夹&#xff08;这里名称为VTK-bin&#xff0c;见前文&#xff09;&#xff0c;找到vtk.jar&#xff0c;这里在VTK-bin/lib下。 新建工程 使用JetBrains的I…

【图】概念、存储结构、广度优先遍历遍历、深度优先遍历 - 详解

目录 前言 一、图 1.1、基本概念 二、图的存储结构 2.1、存储结构 2.1、邻接矩阵&#xff08;考察重点&#xff09; 2.1.1、代码实现 2.2、邻接表 2.3.1、无向邻接表存储 2.3.2、有向图邻接表存储 3.1、图的广度优先遍历&#xff08;层序遍历&#xff09; 3.2、图的…

Wails + Go 实现图形化桌面应用

效果展示 编写一个热点查看程序&#xff0c;包含百度热搜、微博热搜、头条、知乎等&#xff0c;废话不说上效果图&#xff1a; 效果图1&#xff1a; 效果图2 打包大小 涉及技术点 Golang 使用golang 1.9 编写代码 Wails vue3 使用Wails技术实现GUI渲染&#xff0c;页…

网络——网络协议总结

个人简介&#xff1a;云计算网络运维专业人员&#xff0c;了解运维知识&#xff0c;掌握TCP/IP协议&#xff0c;每天分享网络运维知识与技能。座右铭&#xff1a;海不辞水&#xff0c;故能成其大&#xff1b;山不辞石&#xff0c;故能成其高。 个人主页&#xff1a;小李会科技的…

笔记本安装CentOS

目标: 1.利用闲置笔记本 2.省电/提高利用率/不安装图形桌面/最小化安装/附加选项:开发工具 step1&#xff1a;镜像下载 CentOS-7.9 163镜像 阿里云镜像 清华大学镜像 随便选一个 step2: 下载U盘系统盘制作工具Rufus U盘写入镜像/安装 step3: 安装完毕进入系统 …

2023年上半年软考学习总结(超详细)

目录 前言 一、背景1.1上次考试感受&#xff1a;1.2这次考试感受&#xff1a;1.3方法&#xff1a; 二、 过程2.1计算机网络概论计算机组成数据表示相关知识校验码相关知识计算机体系结构网络体系结构OSI/RM和TCP/IP计算机安全性可靠性性能评价 2.2 程序设计语言基础知识编译和解…

如何在华为OD机试中获得满分?Java实现【求最小公倍数】一文详解!

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: Java华为OD机试真题&#xff08;2022&2023) 文章目录 1. 题目描述2. 输入描述3. 输出描述…

【Unity3D】广告牌特效

1 前言 广告牌特效是指&#xff1a;空间中的一个 2D 对象始终&#xff08;或尽可能&#xff09;面向相机&#xff0c;使得用户能够尽可能看清楚该 2D 物体。广告牌特效一共有以下 3 种&#xff1a; 正视广告牌&#xff1a;广告牌始终以正视图姿态面向相机&#xff0c;即广告牌…