类型转换的规则

本文通过一个实际案例探讨了C/C++中整型数据自动转换的问题,特别是当有符号整数与无符号整数进行运算时可能出现的意料之外的结果,并总结了C/C++中的数据类型自动转换规则。
    今天同事有个问题,基本情况就是当OperatorGUI界面操作输入了一个非法值(例如一个负值),居然没有任何错误提示,导致最后log中记录的信息让人无法理解。从信息的处理流程来看,没有任何问题。后来发现是因为程序中有一个计算步骤是用一个unsigned int和输入的数值作了一个相加,然后再对计算结果大小进行判断。由于输入的是负数,负数和unsigned int做算术运算时,被自动转换为了一个大整数,计算的结果肯定也不正确了。
    这让我想到了曾经的一个笔试题,大概是这样的:
    下面的程序的结果是什么:
int fun() {
  unsigned 
int a = 10;
  
int b = -100;
  
int c;
  (a
+b>0? (c=1):(c=0);
  
return c;
}

    正确答案:1。原因就是int b本身是有符号书-100。但是当它和无符号整数a做计算时,他就被自动转化为无符号整数了。也就是说,本身-100是:0xffffff9c,符号位为全1。但是作为无符号数,-100就成为一个硕大的正整数(好像是18446744073709551516),因此a+b得到的结果也是一个硕大的正整数。
    问题解决了,那就回忆一下C/C++里面数据类型自动转换的规则:
1,表达式中,所有小于整型的有序类型的变量在计算之前都会被转换成整型。charshort类型的值,无论有无符号,在计算时都自动转换成int或者unsigned intenum类型也同样。
2,表达式中的数据如果遇到更高级别的数据,就会自动转换为高级别的数据类型。如果我们“定义”一个数据类型表示的范围越大,这个类型的级别越“高”。那么按照从高到低的顺序排列,应该是:long double > double > float > unsigned long long > long long > unsigned long > long > unsigned int > int(注意,有的系统中,longint大小相同,此时unsigned int的等级就会高于long)。
3,赋值语句中,等号右边的值会在运算之前自动转换为等号左边变量的数据类型,然后才开始计算。这个过程可能导致右边的值转为级别更高的数据类型,也可能“降级”。通常“降级”的时候,编译器都会给一个warning提示数据可能会被截断。
4,对于函数,在参数传递时,传入的数据类型会转换为形参的类型;返回的时候,返回的表达式类型也会自动转换为函数返回类型。
5,类型转换改变的是值得类型,而不是对象的类型。例如开头的例子中,只是在计算的时候将-100的值变为unsigned int来计算,本身a这个变量没有变!
    以上是小弟的总结,能力有限,如有不对之处,敬请原谅并指正。
 
C语言中的类型转换分为自动类型转换(隐式换)和强制类型转换,其规则如下: ### 自动类型转换(隐式换) - **赋值时的类型转换**:在赋值运算中,赋值号两边量的数据类型不同时,赋值号右边量的类型将换为左边量的类型。如果右边量的数据类型长度比左边长时,将丢失一部分数据,这样会降低精度,丢失的部分按四舍五入向前舍入。例如无符号数与有符号数之间赋值,若int型占两个字节,无符号数小于32768,赋给int型变量后为正值;无符号数大于等于32768,赋给整型变量后为负整数值;负整数赋给unsigned型变量时,得到的无符号值大于32768 [^2][^3]。 - **整型提升**:char型和short型参与运算时,必须先换成int型 [^2]。 - **算数换**: - 若参与运算量的类型不同,则先换成同一类型,然后进行运算。换按数据长度增加的方向进行,以保证精度不降低。如int型和long型运算时,先把int量成long型后再进行运算。 - 若两种类型的字节数不同,换成字节数高的类型。 - 若两种类型的字节数相同,且一种有符号,一种无符号,则换成无符号类型。 - 所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先换成double型,再作运算 [^2]。 ### 强制类型转换 可以利用强制类型转换运算符将一个表达式换成所需类型,例如:`(double)a`(将a换成double类型)、`(int)(x + y)`(将x + y的值换成整型)、`(float)(5 % 3)`(将5 % 3的值换成float型)。对于从高到低的强制换,实质上就是一个截断的操作,只把低端需要的部分保留,其余的部分直接扔掉 [^3]。 ### 不同数据类型间规则 - **有符号整形和无符号整形之间的换**:在赋值等情况下会按上述赋值时的类型转换规则进行换 [^1][^3]。 - **浮点型和整形之间的换**:在运算时按自动类型转换的算数规则,如所有浮点运算以双精度进行;赋值时按赋值规则换 [^1][^2]。 - **浮点型和浮点型之间的换**:在运算时按自动类型转换的算数规则,所有浮点运算以双精度进行 [^1][^2]。 ```c #include <stdio.h> int main() { unsigned a = 65535; int i = -1; int j = a; unsigned b = i; printf("(unsigned)%u→(int)%d\n", a, j); printf("(int)%d→(unsigned)%u\n", i, b); double c = 3.14; int d = (int)c; printf("(double)%f→(int)%d\n", c, d); return 0; } ```
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值