C++ 学习 关于含无符号数表达式的计算
🌈 哈喽,失踪人口回归
这篇blog 来源于C++ 的学习 当然C语言同样适用
C++ Primer 的笔记
🌿让我们从一个问题开始 如果你回答对了 那么就可以跳过了~
对于下面的问题
//读程序写结果。
unsigned u = 10,u2= 42;
std:: cout << u2 - u<< std::endl;
std::cout <u - u2 << std:: endl;
int i = 10,i2 =42;
std::cout<< i2 -i<< std::endl;
std::cout << i - i2<< std::endl;
std::cout << i - u<< std::endl;
std::cout << u- i<< std::endl;
unsigned k1 = 42,k2 = 10;
std::cout<<k2-k1<<std::endl;
std::cout<<k1-k2<<std::endl;
🤔尝试一下最终输出什么结果
揭晓答案!
32
4294967264
32
-32
0
0
4294967264
32
🤭 你答对了嘛 没有的话 可以接下去看(我刚开始也是懵的其实~)
🌺 首先明确一下,不管是C还是C++ 类型都是很重要的! 所以先看看类型转换相关的内容,然后再来讨论上面无符号表达式转换的内容~
关于类型转化
⭐️C/C++里面类型是很重要的!你能判断出下面每执行一行后,相应变量的值不?(嘻嘻 梅开二度~)
bool b=32;
int i=b;
i=3.14;
double pi=i;
unsigned char c= -1;
signed char c2=256;
答案揭晓!
bool b=32;//b为真
int i=b;//i=1
i=3.14;//i=3
double pi=i;//pi=3.0
unsigned char c= -1;//若char 为8bit c为255
signed char c2=256; //若char 为8bit 那么c2是未定义的 溢出啦
当我们把一个非布尔类型的算术值赋给布尔类型时,初始值为0则结果为false,否则结果为true。
当我们把一个布尔值赋给非布尔类型时,初始值为false 则结果为0,初始值为true 则结果为1。
当我们把一个浮点数赋给整数类型时,进行了近似处理。结果值将仅保留浮点数中小数点之前的部分。
当我们把一个整数值赋给浮点类型时,小数部分记为0。如果该整数所占的空间超过了浮点类型的容量,精度可能有损失。
当我们赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模后的余数。例如,8比特大小的unsigned char可以表示0至255区间内的值,如果我们赋了一个区间以外的值,则实际的结果是该值对 256取模后所得的余数。因此,把-1赋给8比特大小的unsigned char所得的结果是255。
当我们赋给带符号类型一个超出它表示范围的值时,结果是未定义的(undefined)。此时,程序可能继续工作、可能崩溃,也可能生成垃圾数据。
含有无符号类型的表达式
尽管我们不会故意给无符号对象赋一个负值,却可能(特别容易)写出这么做的代码。例如,当一个算术表达式中既有无符号数又有int值时,
那个int值就会转换成无符号数。把int转换成无符号数的过程和把int直接赋给无符号变量一样:
unsigned u= 10;
int i =-42;
std::cout << i+i<< std::endl; //输出-84
std::cout<< u +i << std::endl;//如果int占32位,输出4294967264
//理由是 int 是8个字节 那就是32位 最大为2的32次方-1 也就是4294967295 也就是当-42 先转无符号数(也就是-1对应的是4294967295,依次类推)然后相加
//10+(-42)=10+(4294967295-42+1)=4294967264
关于无符号数和有符号数可以参考这篇blog
在第一个输出表达式里,两个(负)整数相加并得到了期望的结果。
❗️ 在第二个输出表达式里,相加前首先把整数-42转换成无符号数。把负数转换成无符号数类似于直接给无符号数赋一个负值,结果等于这个负数加上无符号数的模。
当从无符号数中减去一个值时,不管这个值是不是无符号数,我们都必须确保结果不能是一个负值:
unsigned ul = 42,u2 = 10;
std::cout<< ul -u2<< std::endl; //正确:输出32
std::cout << u2 - ul<< std::endl;//正确:不过,结果是取模后的值 也是 10-42=10+(-42)=10+(4294967295-42+1)=4294967264
无符号数不会小于0这一事实同样关系到循环的写法。例如,在1.4.1节的练习(第11页)中需要写一个循环,通过控制变量递减的方式把从10到0的数字降序输出。这个循环可能类似于下面的形式:
for (int i = 10;i >= 0;--i)
std:: cout<< i << std::endl;
可能你会觉得反正也不打算输出负数,可以用无符号数来重写这个循环。然而,这个不经意的改变却意味着死循环:
//错误:变量u永远也不会小于0,循环条件一直成立
for (unsigned u= 10; u >= 0;--u)
std::cout<<u<< std::endl;
来看看当u等于0时发生了什么,这次迭代输出0,然后继续执行for语句里的表达式。表达式–u从u当中减去1,得到的结果-1并不满足无符号数的要求,此时像所有表示范围之外的其他数字一样,-1被自动地转换成一个合法的无符号数。假设 int类型占32位,则当u等于0时,–u的结果将会是4294967295。
一种解决的办法是,用while语句来代替for语句,因为前者让我们能够在输出变量之前(而非之后)先减去1:
unsigned u= 11;//确定要输出的最大数,从比它大1的数开始
while (u >0){
//先减1,这样最后一次迭代时就会输出0
--u;
std::cout <<u<<std::endl;
}
改写后的循环先执行对循环控制变量减1的操作,这样最后一次迭代时,进入循环的u值为1。此时将其减1,则这次迭代输出的数就是0;下一次再检验循环条件时,u的值等于0而无法再进入循环。因为我们要先做减1的操作,所以初始化u的值应该比要输出的最大值大1。这里,u初始化为11,输出的最大数是10。
⭐️ 提示:切勿混用带符号类型和无符号类型
如果表达式里既有带符号类型又有无符号类型,当带符号类型取值为负时会出现异常结果,这是因为带符号数会自动地转换成无符号数。例如,在一个形如a*b的式子中,如果a =-1, b=-1,而且a和b都是int,则表达式的值显然为-1。然而,如果a是int,而b是unsigned,则结果须视在当前机器上int所占位数而定。在我们的环境里,结果是4294967295
🤙 好,结束!!撒花
现在回到开始的问题你会分析了不?
//练习2.3:读程序写结果。
unsigned u = 10,u2= 42;
//usigned 8位
std:: cout << u2 - u<< std::endl;//32
std::cout <u - u2 << std:: endl;//10+4294967295-42+1=4294967264
int i = 10,i2 =42;
//int 32位 4294967296-1=4294967295
std::cout<< i2 -i<< std::endl; //32
std::cout << i - i2<< std::endl; //-32
std::cout << i - u<< std::endl; //0
std::cout << u- i<< std::endl;//0
unsigned k1 = 42,k2 = 10;
std::cout<<k2-k1<<std::endl;//10+4294967295-42+1=4294967264
std::cout<<k1-k2<<std::endl;//32
🌈ok,完结~(●’◡’●) 看到这里 点个赞叭 (●’◡’●)