整形在内存中的存储-原码补码反码的理解与应用

news2024/11/25 18:51:20

目录

一、概论

1.1 C语言中基本的数据类型

1.2 类型的基本归类

二、整形在内存中的存储

2.1 原码、反码、补码

2.2 存储补码和大小端存储

三、计算各基本数据类型的范围计算原理

3.1 有符号类型的整形范围

3.2 无符号类型的整形范围

3.3 例题


一、概论

C语言提供了非常多的数据类型,我们可以用sizeof来计算它们在内存中所占的字节数,我们今天想要深入了解它们存储的底层原理。

1.1 C语言中基本的数据类型

char - 字符型 所占字节为1
short - 短整型 所占字节为2
int - 整形 所占字节为4
long - 长整型 所占字节>=4,通常为4或8
long long - 更长的整形 所占字节为8
float - 单精度浮点型 所占字节为4
double - 双精度浮点型 所占字节为8

类型的意义:

1. 使用这个类型开辟内存空间的大小(大小决定了使用范围)。

2. 如何看待内存空间的视角。

简单来说,我们要搞明白不同数据类型是怎么存进去的怎么拿出来的

1.2 类型的基本归类

整形家族:
char
 unsigned char
 signed char
short
 unsigned short [int]
 signed short [int]
int
 unsigned int
 signed int
long
 unsigned long [int]
 signed long [int]

浮点数家族:
float
double

构造类型:
> 数组类型
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union

指针类型:
int *pi;
char *pc;
float* pf;
void* pv;

空类型:
void 表示空类型(无类型)
通常应用于函数的返回类型、函数的参数、指针类型。

二、整形在内存中的存储

2.1 原码、反码、补码

1)原码、反码、补码就是整数的二进制序列;

2)正整数的原码、反码和补码完全一致;

3)负整数的原码、反码和补码不一样,需要相互转换。

4)内存中存储的是补码,拿出来用的是原码

下面我们分别定义正整数a=10,负整数b=-10,由于是int类型,它们都占4个字节,用32个二进制位表示

a的二进制序列,也是它的原码、反码、补码:

b的原码、反码和补码:

结论:

1)正整数的原码、反码和补码是一致的;

2)负整数的原码转化把符号位以外的二进制位按位取反得到反码,反码+1得到补码。

2.2 存储补码和大小端存储

数据在内存中存储,以十六进制位表达:

内存中存储的是变量的补码,我们来验证一下,把a和b的补码转化为十六进制位:

注:a是正数,a的原码反码补码一致。

 注:b是负数,要先写出-10的原码,然后转化为反码,反码再转化为补码。

 验证一下:

结果表明内存中存储的是补码,但是是反过来存储的,这就涉及到大小端字节序的概念

大端存储:数据的位保存在内存的地址中,位保存在内存的地址中。

小端存储:数据的位保存在内存的地址中,位保存在内存的地址中。

对于a来说,

对于b来说,

因此a和b的大端字节序和小端字节序存储分别是:

 

 结论:在当前电脑的机器环境下,数据在内存中是以小端字节序存储的。

一道判断大小端存储的面试题:

请简述大小端字节序的概念,并设计一个程序判断当前机器的字节序。

在上面解释了大小端的概念,那如何判断当前机器的字节序呢?我们想要得到当前变量在内存中存储的十六进制序列,为了这个序列尽可能的简单,我们就定义一个整形变量让它的值为1,那么整形1的十六进制表达是0x00000001

如果是小端字节序存储,那么就是 (低地址) 01     00      00      00(高地址) 

如果是大端字节序存储,那么就是 (低地址) 00     00      00      01(高地址)

我们只想访问其中1个字节,得到整形1的高位(或者低位),解引用看一看到底是1还是0,那么就能判断到底是大端存储还是小端存储

原本的变量是int*类型的,*解引用后得到的是4个字节,那么我们将其强制类型转化为char*类型,*解引用后就只得到1个字节

int main()
{
	int a = 1;
	char* p = (char*)&a;
	if (*p == 1)
	{
		printf("小端字节序存储\n");
	}
	else
	{
		printf("大端字节序存储\n");
	}
	return 0;
}

三、计算各基本数据类型的范围计算原理

 

参考来源:https://www.cnblogs.com/luofay/p/6070613.html

注:1个字节的类型的二进制序列有8位,2个字节的有16位,4个字节的有32位,8个字节的有64位,由于变量在内存中存储的是补码,补码的二进制序列和对应类型所占的字节数量有关,因此各基本数据类型的范围和它们所占字节的大小有关。

3.1 有符号类型的整形范围

我们以char类型举例:

char类型由于只占1个字节的内存,所以它的二进制序列只有8位,所以我们容易列举出char类型二进制序列的所有可能,即从00000000~11111111。

我们一般默认char就是signed char,就是有符号的char,因此它的二进制序列的第一位要看成符号位,那么01111111和1000000就应该是char类型范围的两个边界,如图所示: 

 其实,在这255组可能的序列中,我们除了10000000这个序列无法正常计算出它的原码,其他254组二进制序列我们都可以用正数原反补相同、负数要相互转化的原理来计算出它们的原码以及对应的十进制数,所以规定10000000这个序列的原码对应的十进制数为-128。

因此有符号char类型的范围就是-128~127

剩下short类型、int类型、long类型和long long类型的范围计算原理是一致的,只不过由于它们所占字节数不同,就要用不同长度的二进制序列表示,二进制序列一长,2的所占权重可能就增大,所以范围就相应地比char类型要大的多了

int类型的范围是-2^31 ~ (2^31-1),short类型的范围是-2^15 ~ 2^15-1

3.2 无符号类型的整形范围

我们容易观察表知,无符号类型的范围就是0~a,a是对应有符号类型的范围的长度

比如char的范围是-128~127,unsigned char的范围就是0~255;int的范围是-2^31 ~ (2^31-1),unsigned int的范围就是0~2^32-1;short的范围是-2^15 ~ 2^15-1,unsigned short的范围是0~2^16-1等等。

我们以unsigned char类型举例,与char进行对比:

由于是无符号类型,所以第一位就不需要看成符号位,因此在内存中存储的补码和拿出来用的时候的原码是一致的。

3.3 例题

解题步骤:

1)先写出变量值的原码;

2)根据是正数还是负数,写出反码和补码;

3)根据变量的类型,判断数据是否完全存储进这个变量,不完全存储则发生截断

4)观察这个变量是有符号类型还是无符号类型,对应地发生整形提升:有符号位高位补符号位,无符号位高位补0

5)观察是以什么方式打印出来的(以什么方式使用)以及变量本身是有符号还是无符号,根据补码计算出原码。

例题一

int main()
{
	char a = -1;
	signed char b = -1;
	unsigned char c = -1;
	printf("%d\n%d\n%d\n", a, b, c);
	return 0;
}

解:a和b是一致的,在vs环境下char就是signed char,因此a和b打印出来是一样的。

c是无符号类型,所以在整形提升和最后的原码计算方面和a、b不一致。

 

 例题二

int main()
{
	char a = -128;
	printf("%u", a);
	return 0;
}

解:

例题三 

int main()
{
	char a = 128;
	printf("%u", a);
	return 0;
}

解: 

 

 例题四

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

 解:由于此时i和j都是int类型,可以完全存储数据,所以不需要发生截断

 

 例题五

int main()
{
	unsigned int i = 9;
	for (i = 9; i >= 0; i--)
	{
		printf("%u\n", i);
		Sleep(1000);
	}
	return 0;
}

解:

这是一个死循环,说明循环不仅仅是正常从9执行到0。

i是无符号整形,说明i恒为正数,前9到0是正常的打印,后面的负数有可能转化为正数,所以我们考虑负数转为无符号整数打印出来的是怎样的数。

而且此时也不需要发生截断。

 

 

 

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

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

相关文章

【Java基础学习打卡07】Java语言概述

目录 引言一、Java语言1.Java语言简介2.Java语言优势3.Java能做什么? 二、Java之父三、Java简史1.Java版本时间线2.Java发展重要节点 总结 引言 一、Java语言 1.Java语言简介 Java语言是一种以面向对象为基础的高级编程语言。吸收了C语言的各种优点,又…

【IMX6ULL驱动开发学习】06.APP与驱动程序传输数据+自动创建设备节点(hello驱动)

一、APP与驱动之间传输数据 /*驱动从APP获取数据*/ unsigned long copy_from_user(void *to, const void *from, unsigned long n)/*驱动传输数据到APP*/ unsigned long copy_to_user(void *to, const void *from, unsigned long n)二、使用copy_to_user、copy_from_user在AP…

32908字长文理解Large CV Model:Segment Anything

作者:猛码Memmat 目录 Abstract1. IntroductionTaskModelData engineDatasetResponsible AIExperimentsRelease 2. Segment Anything TaskTaskPre-trainingZero-shot transferRelated tasksDiscussion 3. Segment Anything ModelImage encoderPrompt encoderMask de…

十个实用MySQL函数

函数 0. 显示当前时间 命令:。 作用: 显示当前时间。 应用场景: 创建时间,修改时间等默认值。 例子: 1. 字符长度 命令:。 作用: 显示指定字符长度。 应用场景: 查看字符长度时。 例子: 2. 日期格式化 命令…

【群智能算法改进】一种改进的白鲸优化算法 改进白鲸优化算法 改进后的EBWO[1]算法【Matlab代码#40】

文章目录 【获取资源请见文章第5节:资源获取】1. 原始BWO算法2. 改进的白鲸优化算法EBWO2.1 Logistic映射2.2 透镜成像折射方向学习 3. 部分代码展示4. 仿真结果展示5. 资源获取 【获取资源请见文章第5节:资源获取】 1. 原始BWO算法 白鲸优化算法 (BWO&…

LeetCode —— 206. 反转链表

LeetCode —— 206. 反转链表 一、题目描述: 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2: 输入:head …

【Shiro】第二章 Shiro概述

目录 1、Shiro简介 2、核心组件 1、Shiro简介 【1】什么是Shiro? Shiro是apache旗下一个开源框架,它将软件系统的安全认证相关的功能抽取出来,实现用户身份认证,权限授权、加密、会话管理等功能,组成了一个通用的安全认证框…

华为OD机试真题 JavaScript 实现【租车骑绿道】【2023Q1 100分】

一、题目描述 部门组织绿岛骑行团建活动,租用公共双人自行车骑行,每辆自行车最多坐两人、最大载重 M。 给出部门每个人的体重,请问最多需要租用多少双人自行车。 二、输入描述 第一行两个数字 m、n,自行车限重 m,代…

管理类联考——逻辑——技巧篇——论说文模块

正论模块 一直为社会、企业所重视。正是因为___让我们在应对挑战中超越自我,形成了一种保持可持续发展的能力与定力,涵养了自强不息、卧薪尝胆的品质,弥补了心智和能力的短板。古今中外这样的事例比比皆是/正如__所言“__”(事实证据或引典)…

Mybatis学习之插件

Mybatis学习之插件 Plugins Mybatis中的插件虽然名称叫插件,但实质上是通过动态代理实现的。和我们平时讲的插件概念不一样,但是本质上都是给外部提供接口进行扩展。 MyBatis 允许我们在映射语句执行过程中的某一点进行拦截调用。MyBatis允许我们使用…

【C/C++】引用()的概念和用法

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

推荐几款可以大幅提高开发效率的vscode插件

1、Vue 2 Snippets 这是一款基于vue2的代码片段提示插件&#xff0c;特别好用&#xff0c;可以有效的提高我们的编码速度。 他的能力非常强大&#xff0c;具体还需要我们去看他的文档文档地址 &#xff0c;解锁更多能力。 2、Path Autocomplete 这是一款路劲提示插件 vscod…

计算机网络实验第一课:HTTP和DNS

实验准备 1.先安装好wireshark 2.开启抓包&#xff0c;然后用过滤器选中http。 3.输入http://gaia.cs.umass.edu 网址&#xff0c;摁下回车键。&#xff08;这里我做实验的时候出了点意外&#xff0c;我一开始开着梯子&#xff0c;然后一直都是通过代理访问的网页&#xff…

Spring Security Oauth2.1 最新版 1.1.0 整合 (基于 springboot 3.1.0)gateway 完成授权认证

目录 背景 版本 Spring Boot 3.1 Spring Authorization Server 1.1.0官方文档 基础 spring security OAuth2.0 模块构成 授权方式 集成过程 官方demo 代码集成 依赖 授权服务AuthorizationServerConfig配置 重要组件 测试 查看授权服务配置 访问授权服务 授…

简单实用的快递查询工具,支持批量查询

大家如果遇到快递一直没到的情况&#xff0c;是不是会很心急呢&#xff1f;这时候就要去查询一下快递具体的运输轨迹了&#xff0c;看看自己的快递运输到哪里了。今天小编给大家推荐一款快递信息查询软件&#xff1a;“固乔快递查询助手”&#xff0c;这款软件能够自动识别单号…

管理类联考——英语——知识篇——考研英语熟词生义

考研英语熟词生义 A 1.abandon【生义】放松&#xff0c;沉溺 2.abide【【生义】容忍&#xff0c;经受住 3.abroad【生义】广为流传&#xff0c;传开 4.abrupt【生义】陡峭的&#xff0c;险峻的 5.absent【生义】漫不经心的 6.absolute【【生义】基本的 7.absorb【生义】…

Redis 发布和订阅详细介绍

发布和订阅 发布和订阅是什么 一句话&#xff1a;Redis 发布订阅(pub/sub) 是一种消息通信模式&#xff1a;发送者(pub) 发送消息&#xff0c;订阅者(sub) 接收消息 Redis 客户端可以订阅任意数量的频道 一图胜千言 1、客户端订阅频道示意图 2、当给这个频道发布消息后&am…

[CKA]考试之网络策略NetworkPolicy

由于最新的CKA考试改版&#xff0c;不允许存储书签&#xff0c;本博客致力怎么一步步从官网把答案找到&#xff0c;如何修改把题做对&#xff0c;下面开始我们的 CKA之旅 题目为&#xff1a; Task 在现有的namespace fubar中创建一个名为allow-port-from-namespace的新Netwo…

云原生时代崛起的编程语言Go远程调用gRPC实战

文章目录 概述定义背景特点四种服务方法 实战环境配置proto文件简单RPCToken认证服务器流式RPC客户端流式RPC双向流式RPC 概述 定义 gRPC 官网地址 https://grpc.io/ 源码release最新版本v1.55.1 gRPC 官网文档地址 https://grpc.io/docs/ gRPC 源码地址 https://github.com/g…

【vue3】13-前端路由-Vue-Router的详解: 从入门到掌握

前端路由 前端路由的发展历程认识前端路由&#xff1a;后端路由阶段前后端分离阶段 Vue-Router的使用vue-router的基本使用vue-router的使用过程基本使用的细节补充 路由懒加载分包处理路由的其他属性动态路由路由嵌套路由的编程式导航动态管理路由对象路由导航守卫钩子 前端路…