【C语言】整型提升与char取值范围

整型提升介绍

C语言中整型算术运算总是至少以缺省(默认)整型类型的精度来进行的。为了获得这个精度,表达式中字符、短整型操作数在使用前被转换为普通整型。而这个过程是悄悄发生的。

整型提升的意义:

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

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

通用CPU难以直接实现两个8bit字节的直接加法运算。所以,表达式中各种长度可能小于int长度的整型值,都必须先转换为int或unsigned int,然后才能送入CPU去执行。

举个例子:

char a = 20;
char b = 130;
char c = a + b;
printf("%d\n", c);

根据我们上面说的,在这段代码中,其实会先把a、b提升为整型类型才计算。

怎么整型提升

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

无符号整数提升,高位就补0。

回到我们刚才的例子:

char a = 20;

20本身是个整数,整数存到整型中应该有32个比特位(bit),因为是个正整数,它的原码、反码、补码相同:

00000000000000000000000000010100

但是我们现在要将它存放到char类型(只有1个字节,也就是8bit)中去,会发生截断。

我们只能存下这个:

00010100

 同样的道理,b里面我们只能存的是:

10000010

那么现在,c里面放的是什么?

因为我们已经知道,a+b在具体计算前会先发生整型提升,我们也知道整型提升的规则是:有符号整数的整型提升是按照变量的数据类型的符号位来提升的;无符号整数提升,高位就补0。因为是a、b是有符号整型,所以按照符号位来提升:

00010100 ---> 00000000000000000000000000010100 //因为符号位为0
10000010 ---> 11111111111111111111111110000010 //因为在提升时认为符号位是1
  a + b:      11111111111111111111111110010110
11111111111111111111111110010110 ---> 10010110 //因为c只能存8位,又截断

所以c里面存的是10010110,但是这还没有结束,最后我们要打印的时候用的是%d,这是打印一个有符号的整型,我们此时又要进行提升

10010110 ---> 11111111111111111111111110010110 
//因为%d是有符号整型,提升时按符号位提升,而1被视作符号位

而此时%d打印出来的结果并不是这个二进制序列直接翻译成十进制的结果,因为内存中存储的是补码,而我们要找出它的原码直接翻译的结果才是我们会打印出来的值:

因为现在的符号位上还是1,被当做负整数,所以原码、反码、补码并不相同,我们可以通过将补码取反+1的方法得到原码:

11111111111111111111111110010110 ---> 10000000000000000000000001101001
//取反的规则是符号位不变,其它位取反
10000000000000000000000001101001 ---> 10000000000000000000000001101010
//将取反的结果再加1

最后这个原码直接翻译:因为%d是有符号整数,符号位为1所以是负数,1101010转换为10进制是106,所以最后打印的结果就是-106。

另一种视角(char取值范围)

char a = 20;
char b = 130;
char c = a + b;
printf("%d\n", c);

关于这段代码,通过上面的讲解我们多次感受到了整型提升, 这是我们从内存中存储了什么的角度一步步去看为什么结果是-106的,其实还有另一个角度可以解释结果为什么结果为-106:

我们不要忘记char类型的取值范围,一般情况下char就是指的有符号的char,取值范围是-128~127(而unsigned char范围是0~255,都是256个不同数值)。

(本文不解释为什么是这样)这是我们char能存储的值的示意图,就像一个轮回:

所以其实130大于char的取值,我们无法将其存进b里。

我们可以通过监视看看b存的是什么:

可以看到我们存的值就是-126,那么a+b就变成了-106。

 那么为什么b里面会存为-126呢?在上面我们已经得到了a+b的二进制序列被截断为8bit,也就是c里实际存的二进制序列是:

10010110

在计算器中我们可以观察到这个二进制序列直接翻译为10进制的值是150。

但是对于char而言,这个二进制序列可不是代表150。 为什么?

因为char只能存8bit,且为有符号类型,所以最高位是符号位,1说明是负整数,那么说明存的是补码,原码需要计算,根据取反(符号位不变,其他位按位取反)再+1,我们得到原码是:

10010110 ---> 11101001 ---> 11101010
         取反          加1

最高位是符号位,代表是负数,而剩下的有效位转化为十进制是106。所以原码就是106,

补充:char能存储的补码

我们知道char有8位,而每一位非0即1,所以我们能存的补码就是00000000~11111111,又因为char是有符号的char,所以当最高位变为1的时候我们会将其作为符号位而非有效位,而存的又是补码,在翻译为10进制数的时候要先取反加1得到原码,直接翻译才是其对应的10进制数。

其中10000000的求原码比较特殊,取反加1后我们得到100000000是9位的,而char只能存8位,所以会变为00000000,但是我们却不将其翻译为10进制的0而是-128。除了这个特殊情况外,其它情况都可以正常方式得到原码:

通过这张图,你应该就理解了上面那个“轮回”的图为什么是那样的了。

我们还可以发现,除了127加1得到的是-128的特殊情况,其他时候补码加1就是10进制加1的效果。 

到此,整型提升和char取值范围的讲解就结束了,祝阅读愉快^-^ 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

二叉树—先后序线索化和先后序线索遍历

有了上篇文章的基础,先序和后序的线索化逻辑一样。 代码如下: void preOrderThreadTree(TreeNode* T,TreeNode** pre) {if (T NULL) {;}else {//printf("%c ", T->val);if (T->lchild NULL) {T->ltag 1;T->lchild *pre;}if …

逻辑这回事(一)----编码规范

说明:优先级是M的规则为强制项,优先级为R的规则为建议项。 通用约束 应有全局观念。 优先级:M 说明:你所编写的代码在成为最终硅片上的一部分之前,需要经过许多设计者利用各种各样的工具进行各种各样的处理。有时&…

【知识拓展】ngrok-高性价比的内网穿透工具

前言 使用google colab运行的web应用无法打开进行测试。 第一时间想到是否有相关工具能将内网映射到外网供访问。于是找到了ngrok。 ngrok 是什么,我们为什么要使用它? ngrok官网是一个全球分布的反向代理,无论您在哪里运行,它…

VUE3和VUE2

VUE3和VUE2 上一篇文章中,我们对VUE3进行了一个初步的认识了解,本篇文章我们来进一步学习一下,顺便看一下VUE2的写法VUE3是否能做到兼容😀。 一、新建组件 我们在components中新建一个组件,名称为Peron,…

yolov10 快速使用及训练

参考: https://docs.ultralytics.com/models/yolov10/ ultralytics其实大多数系列都能加载使用: 官方: https://github.com/THU-MIG/yolov10.git 代码参考: https://colab.research.google.com/github/roboflow-ai/notebooks/blob/main/notebooks/train-yolov10-object-…

无人机的相关基础知识(看不懂了 待定以后继续补充)

视频: 【浙江大学】浙大博导带你从0制作无人机_哔哩哔哩_bilibili 什么是无人飞行器 无人机自主导航构架 IMU(加速度计和陀螺仪),可以测出当前的 加速度和角速度 这俩信息再去融合外部传感器 (例如视觉传感器或者雷…

【全网最全】2024电工杯数学建模A题成品论文+前三题完整解答matlab+py代码等(后续会更新成品论文)

您的点赞收藏是我继续更新的最大动力! 一定要点击如下的卡片链接,那是获取资料的入口! 【全网最全】2024电工杯数学建模A题成品论文前三题完整解答matlabpy代码等(后续会更新成品论文)「首先来看看目前已有的资料&am…

水表电表远程抄表是什么?

1.简述:水表电表远程抄表技术性 随着时代的发展,传统式手动抄表方法早已被更为高效、智能化的远程抄表系统所替代。水表电表远程抄表,说白了,就是利用互联网技术完成对水表和电表读数的远程数据采集管理方法,大大提升…

【移动云】5G时代——你我的智慧云

文章目录 0.引言1.移动云简介2.移动云学习资源3.移动云产品介绍3.1 大数据—数据可视化(DataInsight)3.1.1 应用场景3.1.2 产品基本架构3.1.3 优势 3.2 云主机ECS3.2.1 云主机ECS优势3.2.2 云主机主要功能3.2.3 应用场景 4.移动云解决方案4.1 热门案例1&…

BUUCTF靶场[Web] [极客大挑战 2019]Havefun1、[HCTF 2018]WarmUp1、[ACTF2020 新生赛]Include

[web][极客大挑战 2019]Havefun1 考点:前端、GET传参 点开网址,发现是这个界面 点击界面没有回显,老规矩查看源代码,看到以下代码 代码主要意思为: 用get传参,将所传的参数给cat,如果catdog…

浅谈面向对象--知识补充

This关键字 this 内存图 this关键字表示当前对象本身,一般用于类的内部,其内部存在一个地址,指向当前初始化的对象本身。 当new一个对象时,实际上产生了两个引用,一个是供类Dog内部调用其成员变量和成员方法的this关键…

用HAL库改写江科大的stm32入门例子-6-2 定时器外部时钟

实验目的: 熟悉外部时钟的应用。 实验步骤: 创建项目参照前面的文章,集成oled(没有oled,用uart串口传递也可以)选择外部时钟源时钟源参数设置编写代码: 5.1声明全局变量,如果发生定时器中断的时候,在回调…

Python条件分支与循环

大家好,当涉及到编写高效和灵活的程序时,条件分支和循环是 Python 中至关重要的概念。它们允许我们根据不同的条件执行不同的代码块,或者重复执行一组语句。条件分支和循环是测试开发工程师在日常工作中经常使用的工具,无论是编写…

Elasticsearch集群搭建学习

Elasticsearch集群聚合、集群搭建 RestClient查询所有高亮算分控制 数据聚合DSL实现Bucket聚合DSL实现Metrics聚合RestAPI实现聚合 拼音分词器如何使用拼音分词器?如何自定义分词器?拼音分词器注意事项? 自动补全数据同步集群搭建ES集群结构创…

护眼小贴士:学生如何正确使用台灯?

随着电子设备的普及和长时间的用眼,长时间盯着屏幕或学习,眼睛需要不断调节焦距,导致眼睛肌肉疲劳,进而引发视力下降。这种现象在年轻一代甚至青少年中尤为普遍,这种疲劳状态不仅影响眼睛的舒适度,还会导致…

springboot打包目录解析

一、引言 Java开发中我们使用最多的便是spring框架,比如springboot应用。微服务模式下,每个服务都是一个springboot应用,都会被打包成一个可执行jar包。那么我们有多少人尝试去了解过这个可执行jar到底是什么?它的结构是什么样的…

[保姆式教程]使用目标检测模型YOLO V8 OBB进行旋转目标的检测:训练自己的数据集(基于卫星和无人机的农业大棚数据集)

最近需要做基于卫星和无人机的农业大棚的旋转目标检测,基于YOLO V8 OBB的原因是因为尝试的第二个模型就是YOLO V8,后面会基于YOLO V9模型做农业大棚的旋转目标检测。YOLO V9目前还不能进行旋转目标的检测,需要修改代码 PS:欢迎大家分享农业大…

深入解析:如何高效地更新Python字典

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、引言 二、修改字典中的值 三、向字典中添加键值对 四、更新字典的两种方法总结 五、…

python使用jsonpath来查找key并赋值

目录 一、引言 二、JsonPath简介 三、Python中的JsonPath库 四、使用JsonPath查找JSON Key 五、使用JsonPath赋值JSON Key 六、高级用法 七、结论 一、引言 在数据驱动的现代应用中,JSON(JavaScript Object Notation)已成为一种广泛使…