看看这段c#代码:
byte x = 1;
byte y = 2;
byte z = x + y; // ERROR: Cannot implicitly convert type 'int' to 'byte'
在字节(或短)类型上执行的任何数学运算的结果都隐式地转换回整数。解决方案是显式地将结果转换回一个字节:
byte z = (byte)(x + y); // this works
我想知道的是为什么?是建筑吗?哲学吗?
我们有:
Int + Int = Int
长+长=长
浮+浮=浮
Double + Double = Double
所以为什么不呢:
字节+字节=字节
空头+空头=空头?
一点背景知识:我正在对“小数字”(即< 8)执行一个长列表的计算,并将中间结果存储在一个大数组中。使用字节数组(而不是int数组)更快(因为缓存命中)。但是大量的字节强制转换散布在代码中,使得代码更加难以阅读。
C#
ECMA-334指出,只有在int+int、uint+uint、long+long和ulong+ulong (ECMA-334 14.7.4)上,加法才被定义为合法。因此,这些是关于14.4.2需要考虑的候选操作。由于存在从byte到int、uint、long和ulong的隐式强制转换,所有加法函数成员都是14.4.2.1下适用的函数成员。我们必须根据14.4.2.3中的规则找到最佳隐式转换:
将(C1)转换为int(T1)比将(C2)转换为uint(T2)或ulong(T2)更好,因为:
如果T1是int, T2是uint或ulong, C1是更好的转换。
将(C1)转换为int(T1)比将(C2)转换为long(T2)更好,因为从int转换为long存在隐式转换:
如果存在从T1到T2的隐式转换,且不存在从T2到T1的隐式转换,则C1是更好的转换。
因此使用int+int函数,该函数返回int型。
可以说它深埋在c#规范中。
CLI
CLI只对6种类型(int32、native int、int64、F、O和&)起作用。(ECMA-335分区3节1.5)
Byte (int8)不是这些类型之一,在添加之前会自动强制转换为int32。(ECMA-335分区3节1.6)
This was probably a practical decision on the part of the language designers. After all, an int is an Int32, a 32-bit signed integer. Whenever you do an integer operation on a type smaller than int, it's going to be converted to a 32 bit signed int by most any 32 bit CPU anyway. That, combined with the likelihood of overflowing small integers, probably sealed the deal. It saves you from the chore of continuously checking for over/under-flow, and when the final result of an expression on bytes would be in range, despite the fact that at some intermediate stage it would be out of range, you get a correct result.
另一种想法是:必须模拟这些类型上的溢出/欠流,因为它不会自然地发生在最可能的目标cpu上。何苦呢?