Subtracting uint and int and constant folding

安稳与你 提交于 2019-12-08 17:06:41

问题


Based on this interesting question: Addition of int and uint and toying around with constant folding as mentioned in Nicholas Carey's answer, I've stumbled upon a seemingly inconsistent behavior of the compiler:

Consider the following code snippet:

int i = 1;
uint j = 2;
var k = i - j;

Here the compiler correctly resolves k to long. This particular behavior is well defined in the specifications as explained in the answers to the previously referred question.

What was surprising to me, is that the behavior changes when dealing with literal constants or constants in general. Reading Nicholas Carey's answer I realized that the behavior could be inconsistent so I checked and sure enough:

const int i = 1;
const uint j = 2;
var k = i - j; //Compile time error: The operation overflows at compile time in checked mode.
k = 1 - 2u; //Compile time error: The operation overflows at compile time in checked mode.

k in this case is resolved to Uint32.

Is there a reason for the behavior being different when dealing with constants or is this a small but unfortunate "bug" (lack of a better term) in the compiler?


回答1:


From the C# specification version 5, section 6.1.9, Constant Expressions only allow the following implicit conversions

6.1.9 Implicit constant expression conversions
An implicit constant expression conversion permits the following conversions:
* A constant-expression (§7.19) of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant-expression is within the range of the destination type.
• A constant-expression of type long can be converted to type ulong, provided the value of the constant-expression is not negative.

Note that long is not on the list of int conversions.

The other half the problem is that only a small number of numeric promotions happen for binary operations:

(From Section 7.3.6.2 Binary numeric promotions):

  • If either operand is of type decimal, the other operand is converted to type decimal, or a binding-time error occurs if the other operand is of type float or double.
  • Otherwise, if either operand is of type double, the other operand is converted to type double.
  • Otherwise, if either operand is of type float, the other operand is converted to type float.
  • Otherwise, if either operand is of type ulong, the other operand is converted to type ulong, or a binding-time error occurs if the other operand is of type sbyte, short, int, or long.
  • Otherwise, if either operand is of type long, the other operand is converted to type long.
  • Otherwise, if either operand is of type uint and the other operand is of type sbyte, short, or int, both operands are converted to type long.
  • Otherwise, if either operand is of type uint, the other operand is converted to type uint.
  • Otherwise, both operands are converted to type int.

REMEMBER: The int to long conversion is forbidden for constants, meaning that both args are instead promoted to uints.




回答2:


Check out this answer here

The problem is that you are using const.

At run time when there is a const the behavior is exactly as with literals, or as if you had simply hard coded those numbers in the code, so since the numbers are 1 and 2 it casts to a Uint32 since 1 is within the range of uint32. Then when you try to subtract 1 - 2 with uint32 it overflows, since 1u - 2u = +4,294,967,295 (0xFFFFFFFF).

The compiler is allowed to look at litterals, and interpret them different than it would other variables. Since const will never change, it can make guarantees that it otherwise couldn't make. in this instance it can guarentee that 1 is within the range of a uint, therfore it can cast it implicitly. In normal circumstances(without the const) it cannot make that guarantee,

a signed int ranges from -2,147,483,648 (0x80000000) to +2,147,483,647 (0x7FFFFFFF).

an unsigned int ranges from 0 (0x00000000) to +4,294,967,295 (0xFFFFFFFF).

Moral of the story, be careful when mixing const and var, you may get something you don't expect.



来源:https://stackoverflow.com/questions/26386201/subtracting-uint-and-int-and-constant-folding

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!