C生万物 | 揭开【整型提升】神秘面纱

news2024/11/18 0:00:22

在这里插入图片描述

👑作者主页:@Fire_Cloud_1
🏠学习社区:烈火神盾
🔗专栏链接:C生万物

文章目录

  • 一、前言
  • 二、整型提升的意义所在
  • 三、如何进行整型提升❓
  • 四、实战演练🗡
    • 1、深剖两数求和的内部运算
    • 2、三种不同数据类型的整型提升
    • 3、整型提升与sizeof
  • 五、总结与提炼

一、前言

有关隐式类型转换中的整型提升,相信对于很多读者来说比较神秘,但若是了解了这一块的小知识便可以很好地解开你对很多类型转换的一些困惑,清楚数据在内存中是如何发生变化的🔍

  • 首先,在C语言中,整型算术运算总是至少以缺省整型类型的精度来进行的

👉为了获得这个精度,表达式中的字符型短整型操作数在使用之前被转换为普通整型,这种转换称为[整型提升]

二、整型提升的意义所在

🎯表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的操作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。

🎯因此,即使两个char类型的相加,在CPU执行时实际上也要先转换为CPU内整型操作数的标准长度

🎯通用CPU(general-purpose CPU)是难以直接实现两个8比特字节直接相加运算(虽然机器指令中可能有这种字节相加指令)。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为intunsigned int,然后才能送入CPU去执行运算

通过上面的陈述,相信你对整型提升有了一个初步的概念,接下去我们来看看如何去进行一个整型提升👇

三、如何进行整型提升❓

  • 整形提升是按照变量的数据类型的符号位来提升的

对于整型提升来说,整数和负数是不一样的,首先我们来看看正数的整型提升

//正数的整形提升
char c1 = 1;
  • 首先先来写出1的32个二进制位00000000000000000000000000000001,然后将其转换为原码的形式,但是通过上面的学习我们可以知道对正数的原、反、补码是相同的,因此这就是它在内存中的形式
  • 但是可以看到现在要将这个整数1给到一个char类型的变量c2,此时,此时就会发生一个【截断】的现象,因为一个字符型的数据在内存中只占1个字节,也就是8个比特位,所以在截断之后就只剩下00000001
  • 接下去若是要去使用这个c1的话就会进行一个整型提升,此时在八个比特位的首部填充24个符号位,以达到整型4个字节32个比特位在内存中的要求,那么此时提升之后的结果便是00000000000000000000000000000001可以看出又回到了原来的1,不过若是你不去使用这个c1的话是不需要进行整型提升的

接下去再来看看负数的整型提升

//负数的整形提升
char c2 = -1;
  • 那对于负数其实也是一样,-1 在内存中的32位二进制补码为11111111111111111111111111111111。同理,将其给到一个整型的变量之后就会发生截断即为11111111
  • 那这个时候再进行一个整型提升就和正数不一样了,因为负数的符号位为1,而整型提升在高位是要补充符号位,所以会在前头加上24个1,那其实也就变回了和之前-1的补码一般的样子,为32个1

好,说完了该如何去进行整型提升之后我们就可以去代码段中看看到底是如何进行的

四、实战演练🗡

1、深剖两数求和的内部运算

首先来看第一个,我们要去计算两个整数的和,但是呢却要放到char类型的变量中去,那会发生什么化学反应呢🔮

int main(void)
{
	char a = 5;
	char b = 126;
	char c = a + b;
}
  • 根据上一小节的讲解,相信你已经知道编译器第一步会做什么了,首先的话就是分别写出这两个整数的32个比特位,接着转换为补码的形式,正数三者均一致。然后因为要给到一个char类型的变量,所以会进行一个【截断】
00000000000000000000000000000101 - 5
——> 00000101 - 5【截断】
00000000000000000000000001111110 - 126
——> 01111110 - 126【截断】
  • 接下去我们要开始去使用到这两个字符型的变量了,使用它们进行一个加法运算,那么此时就会发生一个[整型提升],在高位补充24个符号位之后就变成了下面这样,然后便可以对它们去进行一个运算了
//到了内存中开始计算 —— 整型提升(正数)
00000000000000000000000000000101 - 5
00000000000000000000000001111110 - 126
  • 那在运算出来之后呢在计算机中是一个补码的形式,输出来便得是一个原码的形式,由于正数三者是一致,所以不发生改变(一强调这点是因为想让读者搞懂每一步)其实这时可以看到运算出来的数字是正确的,5 + 126 = 131
  • 可是呢可以看到左边又是拿了一个char类型定义的变量在接受这个运算后的结果,因此便又会发生一个【截断】,就只剩下1个字节8个比特位
  • 那其实在这个地方如果我用一个整型变量去接收一下然后再用%d做一个打印,那么此时就会输出正确的内容131
00000000000000000000000010000011 - 131
10000011 - 131【截断】

可是呢,我就是不用整形去接收,就是玩😆用字符型去接受,然后再用%d去打印(“主要还是为了加深知识点的灵活运用”)

printf("c的整数打印形式为:%d\n", c);
  • 那在若是在这个时候又要去进行打印的话,又要放到内存里面去运算了,调用这个printf()库函数其实也算是一个运算,也要放到内存里面去,然后这个变量c又不是整型,所以此时呢就又会发生一个[整型提升]
  • 此时就需要去补充10000011前面的24个符号位了
//整型提升(负数)
11111111111111111111111110000011 - 补码
11111111111111111111111110000010 - 反码
10000000000000000000000001111101 - 原码
  • 然后变要将这个32个二进制位以十进制的形式打印出来,可是计算机中的运算是采取补码的形式,打印输出的话就要采取补码的形式了,所以此时就需要将这个补码转化为原码了,可以看到这是一个负数的补码,所以转化为原码的时候要小心了,需要将补码-1然后再除符号位外均做取反
  • 此时再去转化为十进制的形式输出便是-125,我们来看看结果【全体起立👮】

在这里插入图片描述

2、三种不同数据类型的整型提升

接下去再来看看第二个栗子🌰

  • 上面呢我们只说到了字符类型的整型提升,下面呢我们再来看看短整型,它们都是属于整型数据类型的一种
  • 可以看到定义了三个变量,分别是字符型、短整型、整型,然后初始化了一个十六进制的数据,那我们可以将其转换为二进制的形式便为10110110,那其实到这里我就已经可以看出答案是多少了,只有最后一个if语句会进去,其余的都不成立
int main()
{
	char a = 0xb6;
	short b = 0xb600;
	int c = 0xb6000000;
	if (a == 0xb6)
		printf("a");
	if (b == 0xb600)
		printf("b");
	if (c == 0xb6000000)
		printf("c");
	return 0;
}

在这里插入图片描述

  • 好,来解释一下为什么我一眼就可以看出最后的结果是多少,并不是因为我知道结果,而是我看到了这个十六进制的b,因为它的二进制为1011,可以看到首尾是为0,那么当这个变量a参与运算的时候就会发生一个[整型提升],在上面我说到过对于负数的整型提升和正数不一样,填充符号位后均为1,那么再转化为原码从计算机输出之后就一定不会是原来的值了,会发生一个改变👈
  • 对于char ashort b它们均不是一个整型int类型的数据,所以都会发生一个[整型提升],不过int c它就是一个整型的变量,所以是不会发生变化的

通过这个例子相信你对整型提升一定有了更加深刻的理解

3、整型提升与sizeof

最后一个小案例我们和sizeof做一个结合,顺便再回顾一下前面的知识点📜

int main()
{
	char c = 1;
	printf("%u\n", sizeof(c));
	printf("%u\n", sizeof(c + 1));
	printf("%u\n", sizeof(+c));
	printf("%u\n", sizeof(-c));

	return 0;
}

在这里插入图片描述

  • 通过运行结果可以看到,有三个结果发生了整型提升,首先对于sizeof(c)很明确,计算的就是char这个数据类型的字节长度,也就是1,可以对于下三个结果为什么会发生整型提升呢?我们来分析一下🔍
  • 对于c + 1来说它是一个表达式,上面说到过若是一个char类型或者是short类型定义的变量参与了运算,那在内存中就会发生一个整型提升,那如果这是一个表达式的话也就相当于是参与了运算,整型提升后变为4个字节,具体细节不做展开
  • 那对于+c-c来说就是我们前面说到过的单目操作符中的+-操作符,和一个操作数结合也可以说它是一个表达式,那么同理也会进行一个整型提升

但是我再将它们变个形却又不会发生【整型提升】了,一起来看看👇

char c = 1;
printf("%u\n", sizeof(c + 1));
printf("%u\n", sizeof(+c));

printf("-------------------\n");
printf("%u\n", sizeof(c = c + 1));
printf("%u\n", sizeof(++c));

在这里插入图片描述

  • 可以看到,若是将c + 1改换成了c = c + 1,就不会发生整型提升了,这是为什么呢?因为对于c + 1这个表达式来说确实会发生整型提升,但是呢我又将这个表达式计算后的结果放到c里面去,还记得我在讲述【sizeof()】的时候说到它里面的表达式是不会运算的吗,所以整个表达式的结果其实就是sizeof(c)的结果,和上面所列出的第一个是一样的
  • 再来看看这个++c,那又有同学会产生疑惑,为何+c会发生整型提升,但是++c却不会呢,其实对于++c来说就等价于c = c + 1,那其没有发生整型提升的原因相信你已经清楚了

以上就是有关【整型提升】要介绍的所有内容,看完这些相信你对计算机内部隐式类型转换一定有了一个深刻的了解😀

五、总结与提炼

好,我们来总结一下本文所学习的有关整型提升的内容

  • 首先在开篇讲到了在C语言中为了获得缺省整型类型的精度,对表达式中的字符型和短整型会采取一个整型提升
  • 接着我们谈到了整型提升的意义所在是为了让CPU中的【算术逻辑运算单元ALU】获得一个整型操作数的标准长度,以此来达到更好的计算
  • 了解了什么是整型提升之后,然后便讲到了如何去进行一个整型提升,也就是当这个char类型或short类型的变量参与运算的时候,便会将其放入内存中,此时也就会发生一个整型提升
  • 最后,在我们知道了何时会发生整型提升时,便去具体的场景中观察它的过程,在第一个实例中带大家一步步地理解了两数进行相加在内存中会发生一个怎样的数据转变;在第二个实例中又再度看了short和char类型与int类型在运算时会发生的不同变化;最后一个实例,又和先前讲到过的sizeof操作符做了一个结合,更加深度地理解了[整型提升]的作用,揭开了它的神秘面纱

文章到这里就结束了,近期遇到了有关【整型提升】的内容,特此总结做个分享
2023年1月3日记4

在这里插入图片描述

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

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

相关文章

机器学习:线性回归分析女性身高与体重之间的关系

机器学习:线性回归分析女性身高与体重之间的关系 创作不易,觉得文章不错或能帮到你学习,记得点赞 收藏哦 文章目录机器学习:线性回归分析女性身高与体重之间的关系一、实验目的二、实验原理三、实验内容四、实验环境五、实验步骤…

C++ 入门基础

✨个人主页: Yohifo 🎉所属专栏: C修行之路 🎊每篇一句: 图片来源 The longest way must have its close,the gloomiest night will wear on a morning. 最长的路也有尽头,最黑暗的夜晚也会迎来清晨。 文…

擅长做财务分析的BI软件有哪些?

财务分析是企业数据分析中的一个重要板块,所以基本上BI软件都能做基础的财务数据分析,比如说帆软、永洪、思迈特等,但要说到系统化地、高效地做企业财务分析,还是要看奥威BI软件。 之所以说BI财务分析软件看奥威BI,是…

【万文全解】Java集合源码解析【HashMap】【ArrayList】【JDK源码集合部分】

Java集合源码解析 本文主体部分是作者跟着B站韩顺平老师的课程总结而来,中间穿插自己的理解还有网上各类优质解答 第一节:集合介绍与集合体系图 集合与数组对比(引入集合的目的) 数组: 长度必须指定,一…

javaEE 初阶 — TCP 流套接字编程

文章目录1. TCP 流套接字1.1 ServerSocket API1.2 Socket API1.3 TCP中的长短连接2. TCP 版本的回显服务器3. TCP 版本的回显客户端4. 如何给多个客户端提供服务1. TCP 流套接字 TCP 不需要一个类;来表示 “TCP” 数据报。 TCP 不是以数据报为单位进行传输的&#x…

拉伯配资“十年一剑”硕果累累 我国注册制改革迈入新征程

从2013年党的十八届三中全会明确提出“推动股票发行注册制变革”,到首届进博会上宣告科创板试点注册制,再到本年2月1日全面施行股票发行注册制变革正式发动,十年风雨兼程,我国注册制逐渐从“试点”走向“全面”。 2013年11月&…

编译链接过程详解

写在前面: 大家都知道,我们在编译器中建好一个**.c或.cpp 文件**,经过编译之后就可以运行了,也就是说我们写的.c 文件最后会变成一个可执行程序,那么 .c 或者 .cpp 文件是如何变成一个可执行程序的呢? 主要…

Vue计算属性和监视属性

目录 计算属性computed 监事属性 深度监视 计算属性computed 计算属性: 定义:要用的属性不存在,要通过已有属性计算得来 2、原理:底层借助了Object.defineproperty方法提供的getter和setter 3、get函数什么时候执行? 1、初…

移动硬盘修复的有效方法,恢复移动硬盘的数据这么做!

硬盘是计算机中的存储设备,是非常重要的部分。当硬盘发生故障,很可能会导致我们电脑里面的数据丢失。所以移动硬盘发生故障,我们一定要想办法修复它。 有没有什么操作方法,我们自己也可以简单进行?移动硬盘修复其实也…

mariadb数据库删除恢复过程

不作不死,不小心使sqlyog导数据选错服务器。把生产机的数据全部删除了。可怕的数据没有做其他过多的备份,只是每天自动crontab 备份。该怎么办呢?头脑一片空白。快, 赶紧看看日备份有没有。马上切换到备份目录,喜出望外…

构建指标体系是一套数据分析的框架,比如看哪些指标,这些指标变化了就会反映什么问题,是这样的吗?

指标体系是指由若干个反映企业业务运营特征的相对独立又相互联系的统计指标所组成的有机整体。近年来,各类企业逐渐认识到业务指标的重要性,从管理者们长期关注的企业绩效考核,到用来体现信息化水平的数据可视化大屏,其背后都离不…

【IoT】寻光智能车与循迹智能车

1、寻光智能车 功能说明 智能寻光小车,智能识别光线强弱,实现小车永远向光最强的地方行走,到光源处小车自动停止。基本车体为三轮、二驱、双层机构。主控芯片采用最常用的51单片机; 驱动采用L9110驱动芯片驱动两个减速直流电机…

Veeam ONE v12 发布 (含下载) - 面向所有工作负载的 IT 监控解决方案

Veeam Availability Suite v12 请访问原文链接:https://sysin.org/blog/veeam-one-12/,查看最新版。原创作品,转载请保留出处。 作者主页:www.sysin.org 概述 保持全面可视性和控制力,以高效执行管理、优化、计划和…

域渗透漏洞

一、域内提权漏洞 (CVE-2021-42287和CVE-2021-42278) 1.1 漏洞介绍 1.1.1 CVE-2021-42278 主机账户的名称尾部应该有一个 $(即 sAMAccountName 属性),但是域控对此属性并没有任何验证来确保是否带有 $,这允许攻击者模拟域控主机账户。 1.1.2 CVE-2021-42…

python带你制作自动答题程序,速度超越98%人

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 目录前言环境使用:模块使用:自动答题思路步骤:代码展示尾语 &#x1f49d;环境使用: Python 3.8 –> 解释器 <执行python代码> Pycharm –> 编辑器 <写python代码的> 模块使用: import requests —&g…

Springboot_vue摄影作品图片展示交流平台

前后端通讯一般都是采取标准的JSON格式来交互。 前后端分离 的核心思想是前端页面通过 ajax 调用后端的 restuful api 进行数据交互&#xff0c;而 单页面应用&#xff08;single page web application&#xff0c;SPA&#xff09;&#xff0c;就是只有一张页面&#xff0c;并在…

https解决方案-利用keytool生成证书

https解决方案 1:什么是HTTPS&#xff1f; HTTPS其实是有两部分组成&#xff1a;HTTP SSL / TLS&#xff0c; 也就是在HTTP上又加了一层处理加密信息的模块&#xff0c;并且会进行身份的验证。 2:什么是自签名证书&#xff1f; 就是自己生成的证书&#xff0c;并不是官方…

计算机中的大小端存储

在讲C语言的时候&#xff0c;有讲到大小端的内容&#xff0c;这里呢对大小端的相关内容进行了整理&#xff0c;有需要的可以参考一下&#xff01; 大端和小端来自一个小故事&#xff1a;端模式(Endian)的这个词出自Jonathan Swift书写的《格列佛游记》。这本书根据将鸡蛋敲开的…

mysql导致索引失效的常见情况以及命名规范索引计划分析

1、失效的情况 1.前导模糊查询不能利用索引(like ‘%XX’或者like ‘%XX%’) 假如有这样一列code的值为’AAA’,‘AAB’,‘BAA’,‘BAB’ ,如果where code like %AB’条件&#xff0c;由于前面是 模糊的&#xff0c;所以不能利用索引的顺序&#xff0c;必须一个个去找&#xf…

虚拟机的Linux安装redis

1&#xff0c;下载redis 可以去官网下载压缩包 2&#xff0c;环境准备 我看很多文章都说要安装yum&#xff0c;但是在终端界面一直都是安装失败&#xff0c;后面才知道我的虚拟机是Ubuntu版本&#xff0c;而Ubuntu版本一般不使用yum命令&#xff0c;一般都是使用apt-get命令…