Subtracting uint and int and constantly folding

Based on this interesting question: Adding int and uint and viewing with constant bending, as mentioned by Nicolas Carey , I came across a seemingly inconsistent compiler behavior:

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 described in the answers to a previously asked question.

What surprised me was that the behavior changes when dealing with literal constants or constants in general. Reading Nicholas Carey's answer I realized that behavior can be inconsistent, so I checked and am pretty sure:

 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, Uint32 allowed.

Is there a reason why the behavior differs from the relation to constants or is it a small but unsuccessful "error" (lack of a better term) in the compiler?

+8
c #
source share
2 answers

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

6.1.9. Implicit Constant Expression Conversions
The implicit conversion of constant expressions allows the following transformations:
* A constant expression (Β§7.19) of type int can be converted to type sbyte , byte , short , ushort , uint or ulong if 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 if the value of the constant expression is not negative.

Note that long not on the int conversion list.

The other half of the problem is that for binary operations, there is only a small number of numerical promotions:

(From Section 7.3.6.2 Binary Numeric Promotions):

  • If either operand is of type decimal, the other operand is converted to decimal or a binding 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 any 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 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: Converting an int to long forbidden for constants, which means that both arguments move to uint s instead.

+4
source share

Check this answer here

The problem is that you are using const.

At run time, when there is a constant, the behavior happens just like with literals, or as if you just encoded these numbers in the code, so since the numbers are 1 and 2, it goes to Uint32, since 1 is inside the uint32 range. Then, when you try to subtract 1 - 2 with uint32, it overflows as 1u - 2u = +4,294,967,295 (0xFFFFFFFF).

The compiler is allowed to view the letters and interpret them differently than other variables. Since const will never change, he can make guarantees that he otherwise could not have made. in this case, it can guarantee that 1 is within the uint range, so it can use it implicitly. Under normal conditions (without const), he cannot guarantee this guarantee,

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

unsigned int changes from 0 (0x00000000) to +4 294 967 295 (0xFFFFFFFF).

The moral of the story, be careful when mixing const and var, you can get what you do not expect.

+3
source share

All Articles