当前位置: 首页 > news >正文

C/C++中有符号数隐式类型转换成无符号数需注意的问题

文章目录

  • 前言
  • 举例
    • 隐式转换
    • 显示转换
  • 问题
  • 查找原因
  • 总结

前言

隐式类型转换转换是一个挺基础的概念,即使对于初学者来说都不会陌生,一般情况下是指数据类型的转换是由编译系统自动进行的,不需要人工干预的类型转换方式。与之相对的是强制类型转换,在进行转换时必须使用强制类型转换运算符进行转换,这种也被称为显式转换。

举例

隐式转换

short sn = 999;
int n = sn;

显示转换

float f = 110.741f;
int n = (int)f;

这两种转换方式平时经常用到,不管是函数传参时进行转换,还是数学计算时进行强转,一直也没有发现有什么问题,直到昨天遇到了一个有符号数隐式转换成无符号数时,才发现这里也是一个知识盲点,当时脑瓜儿嗡嗡的,怎么连隐式类型转换也这么陌生了呢?

其实隐式类型转换一般发生在小类型转换成大类型时,有个常用的关系链 char -> short -> int -> long -> float -> double,当关系链条中出现无符号数字时,情况有些难以理解了(实际上是有符号数字的锅)。

问题

看一下这几行代码,如果你能准确说出程序的输出值,那么你已经掌握了这个知识点,后面的内容可以不用看了:

#include <iostream>
using namespace std;

int main()
{
    char c = 128;
    unsigned int n = c;
    cout << n << endl;

    return 0;
}

这段代码的输出值是 4294967168,发生了啥?也就是说老板给你发工资时,本来想发128块,但是发工资的函数参数是 unsigned int 类型的,结果就给你发了 4294967168,一下就实现了40多个小目标。

查找原因

针对上面的代码我们改写一下,把变量 c 换成无符号类型:

#include <iostream>
using namespace std;

int main()
{
    unsigned char c = 128;
    unsigned int n = c;
    cout << n << endl;

    return 0;
}

这次的输出值变成了 128, 符合我们的预期,回过头来再看看刚才出错的代码,区别就是变量c是否有符号,结果差了好几十亿。

这里导致结果差异的原因实际上是符号位引起的,如果是无符号数字,从小类型到大类型隐式类型转换的结果数字都不会变,但是如果是有符号的数字,在转换成大类型数字的时候就要考虑符号位了,就以第一段代码为例来解释这个现象。

char c = 128; 这一句实际上已经超出了变量 c 的范围,因为变量c是有符号数字,所以它的范围是-128~127,这里赋值成128,实际在内存中的bit排列是 10000000,而有符号数的第一位bit表示正负号,这里是1表示这是一个负数,计算机存储负数是以补码的形式存储的,那么把这个数据按位取反再加1,得到 1000000 还是原来的数字,好神奇哦!

不过这里就可以计算出 c 实际上代表-128,那么它在隐式类型转换成更大的有符号数字时,需要保证值不变,一个int的-128怎么表示呢?根据补码的定义应该是11111111 11111111 11111111 10000000,这个数字再转换成 unsigned int 就是前面提到的 4294967168 啦。

总结

  • 有符号数字在转换成范围更大的无符号数字时需要注意转换所得数值是否正确,失之毫厘差之千里。
  • 总结一个规律,有符号的整形数字在进行隐式类型转换时实际上是在数字的二进制表示前面补充符号位。

==>> 反爬链接,请勿点击,原地爆炸,概不负责!<<==

一个人不能做完所有的事情,但是所有人都可以做一些事情,怕什么真理无穷,进一寸有进有一寸的欢喜~

相关文章:

  • system_clock::now()和time()时间函数混用带来的踩坑经历
  • 2020年终总结!新的起航,新的征程
  • 在比较Linux和Windows命令差异时意外发现了Windows Terminal
  • 记一次解决Intel 9462无线网卡的笔记本安装Ubuntu16.04后无法连接WIFI问题的艰难历程
  • 启用make多任务参数让构建过程加速完成
  • C++中一些方便的算法函数和吃不够的语法糖
  • C/C++中string和int相互转换的常用方法
  • TCP/IP协议簇中的子网掩码有什么作用
  • Go环境配置时遇到的GOPATH路径以及包管理问题
  • linux环境下的mount命令到底有什么玄机
  • Python中int、str、bytes相互转化,还有2进制、16进制表示,你想要的都在这里了
  • 解决git命令会将结果输出到单独窗口必须按q才能退出的问题
  • C++中反向遍历map时怎样删除元素
  • C++中常见的字符判断与处理方法
  • 写给自己的KMP——C++版本
  • [Vue CLI 3] 配置解析之 css.extract
  • [数据结构]链表的实现在PHP中
  • 【跃迁之路】【733天】程序员高效学习方法论探索系列(实验阶段490-2019.2.23)...
  • java中的hashCode
  • Laravel Mix运行时关于es2015报错解决方案
  • Markdown 语法简单说明
  • MySQL数据库运维之数据恢复
  • node学习系列之简单文件上传
  • Redis中的lru算法实现
  • vuex 学习笔记 01
  • Web设计流程优化:网页效果图设计新思路
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 仿天猫超市收藏抛物线动画工具库
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 浮现式设计
  • 基于 Babel 的 npm 包最小化设置
  • 计算机在识别图像时“看到”了什么?
  • 每天一个设计模式之命令模式
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 世界上最简单的无等待算法(getAndIncrement)
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • 做一名精致的JavaScripter 01:JavaScript简介
  • hi-nginx-1.3.4编译安装
  • #define
  • #git 撤消对文件的更改
  • #LLM入门|Prompt#1.7_文本拓展_Expanding
  • (C语言)深入理解指针2之野指针与传值与传址与assert断言
  • (附源码)node.js知识分享网站 毕业设计 202038
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • (转)关于如何学好游戏3D引擎编程的一些经验
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .jks文件(JAVA KeyStore)
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .NET Core 通过 Ef Core 操作 Mysql
  • .Net调用Java编写的WebServices返回值为Null的解决方法(SoapUI工具测试有返回值)
  • .net经典笔试题
  • .Net开发笔记(二十)创建一个需要授权的第三方组件
  • .NET上SQLite的连接
  • .NET实现之(自动更新)
  • @staticmethod和@classmethod的作用与区别