在java里,x += 1与x = x + 1相同,但是是有一点区别,只不过容易被忽略。如下例:
1 | public class TestCompound |
而此处的x = x + 1处就会在编译期报错,因为java编译器认为x + 1是int型的,把int型的赋给short型,类型不兼容,就会报错,要赋值就需要一个强制类型转换,那么在此,二个表达式的区别就看出来了,x += 1,这里暗含了一个自动的类型转换,它会自动把右边的值转换成左边的类型,所以在第一个例子中没有报错,而第二例子中的表达式不会自动转换类型,报错就是必然的了。java的类型转换精度小的向精度大的进行转换,字节长度小的向字节长度大的转换,这里x + 1,x是short类型,x + 1之后编译器认为可能会造成溢出编译器做一个扩宽转换(widening conversion),x + 1的结果值直接向int进行类型,结果在赋值的同时发现x是short类型,这里出现了赋值类型不匹配,造成错误的出现。
C语言中也有一个类型转换的规则在,而且在很多的时候容易引起错误的结果,就是隐式类型提升(TypePromotion),先看一段代码:
1 |
|
可能有很多像我这样的菜鸟级选手就会说,输出的是2,也就是if判定是成立的,testValue=array[0]
其实并非如此,promotion <= GET_LEN这个表达式包含一个隐式的类型提升,导致结果是testValue == 3,也就是testValue == array[1];因为sizeof的返回一个size_t类型,也就是unsigned int 类型,也就是GET_LEN宏得到的结果就是unsigned int类型,而表达式的左边promotion是一个int,那么在二者比较的时候,编译器会做一个算术的类型转换,右侧的类型unsigned和而promotion是signed的,有符号的会向无符号的类型转换,那么promotion会提升成unsigned int类型,那么编译器就会把-1解释为一个很大的正整数,也就会有testValue == 3的结果了,想要消除这个错误给GET_LEN一个强制类型转换就可以了。同样的例子还有,看代码:
1 |
|
strlen的返回值也是size_t类型,像上边所说的相同,if判定中左边的表达式strlen(str) - 10的结果会被隐式提升为size_t类型,也就是不会出小于0的情况,在这种情况也,if判定永远成立,这种情况下要么改成strlen(str) > 10, 要么对表达式做强制类型转换。很多时候这种错误会浪费我们很多时间,所以尽量显式的保持类型一致。