问题:
代码如下:
int i = 23;
float f = 3.14;
if (i == f) // 执行某段代码
编译器会将i转换成float类型,然后比较这两个float的大小,但是float能够表示所有的int吗?为什么没有将int和float转换成double类型进行比较呢?
回答:
在整型数的演变中,当int
变成unsigned
时,会丢掉负数部分(有趣的是,这样的话,0u < -1
就是对的了)。
和C语言中的大部分机制(在C++中得到继承)一样,就硬件操作而言,常见的算术转换应该简明易懂。C语言的发明者精通他们所使用机器上的汇编语言,他们编写的C语言对他们和像他们一样编写程序的人有直接的意义,直到使用汇编语言编写(诸如UNIX内核)的程序时。
现如今,一般来说,处理器并不具有混合类型的指令系统(如float和double相加、比较int和float,诸如此类),因为如果这样做造成芯片晶圆的巨大浪费——如果你想支持更多不同的类型,你不得不实现更多的操作码。然而,在实际中,你只有实现"add int to int"、“compare float to float"和"multiply unsigned with unsigned"等功能的常见指令,这使得优先进行算术转换变得很有必要——它们是指令系统中两种类型的映射关系,它们中的大部分很有用处。
从习惯编写低级别机器代码的编程人员的角度来说,如果有了混合类型,那么在一般情况下最有可能使用的汇编指令就是那些只需要进行最少类型转换的指令。其中,有一种特殊情况就是浮点数的转换,特别是在20世纪70年代早期,当时C语言正在被开发,计算机运行速度很慢,而浮点数的计算是通过软件完成的,所以进行转换的成本很高。这拖慢了常用算术运算的转换开发——当时只有一种操作数实现了转换(这个例外就是long到unsigned int的转换,这种转换没有任何要求,在大部分机器上都可以进行。当然并不是全部,因为总有例外情况)。
所以,编写常用的算术转换是为了完成汇编程序员在大部分时间需要做的事情:即有两种不匹配的类型,将一种转换成另一种。这也就是汇编代码所做的事情,除非有特别原因需要进行其它类型转换。对于那些习惯编写汇编代码的人来说,除非是特殊需要,才会被迫去编写一种不同的类型转换。显然,这种情况下提出编写转换是很自然的事情。虽然,你可以简单地写成这样
if((double) i < (double) f)
顺便提一下,在这个问题中有趣的是,unsigned
的优先级高于int
,所以把int
和unsigned
进行比较时,最终进行的是unsigned类型的比较(开头提到的0u < -1
就是这个道理)。我猜测这可能是在早些时候(计算机发展初期),当时的人们认为unsigned
比int
在所表示的数值范围上受到的限制更小:现在还不需要符号位,所以可以使用额外的位来表示更大的数值范围。如果你觉得int
可能会溢出,那么就使用unsigned好了——在使用16位表示的ints时这个担心会更明显。
via: stackoverflow
作者:wintermute 译者:KayGuoWhu 校对:wxy
本文由 LCTT 原创翻译,Linux中国 荣誉推出