今天同事有个问题,基本情况就是当Operator在GUI界面操作输入了一个非法值(例如一个负值),居然没有任何错误提示,导致最后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;
}
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,表达式中,所有小于整型的有序类型的变量在计算之前都会被转换成整型。char和short类型的值,无论有无符号,在计算时都自动转换成int或者unsigned int。enum类型也同样。
2,表达式中的数据如果遇到更高级别的数据,就会自动转换为高级别的数据类型。如果我们“定义”一个数据类型表示的范围越大,这个类型的级别越“高”。那么按照从高到低的顺序排列,应该是:long double > double > float > unsigned long long > long long > unsigned long > long > unsigned int > int(注意,有的系统中,long和int大小相同,此时unsigned int的等级就会高于long)。
3,赋值语句中,等号右边的值会在运算之前自动转换为等号左边变量的数据类型,然后才开始计算。这个过程可能导致右边的值转为级别更高的数据类型,也可能“降级”。通常“降级”的时候,编译器都会给一个warning提示数据可能会被截断。
4,对于函数,在参数传递时,传入的数据类型会转换为形参的类型;返回的时候,返回的表达式类型也会自动转换为函数返回类型。
5,类型转换改变的是值得类型,而不是对象的类型。例如开头的例子中,只是在计算的时候将-100的值变为unsigned int来计算,本身a这个变量没有变!
以上是小弟的总结,能力有限,如有不对之处,敬请原谅并指正。