Search code examples
c#ulong

Why can't I assign (1<<31) to an ulong var? (Error 25 Constant value ... cannot be converted ...)


Why does this assigning produce a comile error: Constant value '-2147483648' cannot be converted to a 'ulong' and I have to use unchecked (...) for this case?

ulong xDummy30 = (1 << 30); // works
ulong xDummy31 = (1 << 31); // ERROR 25 Constant value '-2147483648' cannot be converted to a 'ulong'
ulong xDummy32 = (1 << 32); // works

Using this instead works:

ulong xDummy31a = unchecked((ulong)(1 << 31));
// or
ulong xDummy31b = (1ul << 31); //  comment from Regis Portalez

Edit
The Question Why do I have to cast 0 (zero) when doing bitwise operations in C#? has a similar answer and the reason for the observed behaviour is the same. But they are different questions.


Solution

  • According to MSDN ulong reference all your integer literals 1, 30, 31 are regarded as int:

    When an integer literal has no suffix, its type is the first of these types in which its value can be represented: int, uint, long,

    According to MSDN << operator the result of the << operation is also an int. When yo shift by 30 the result is positive, when shifting by 31 the result is a negative int which can't be assigned to an ulong.

    Edit: HVD pointed me an error in the following. Thanks HVD!

    Start Error - When shifting 32 bits, the compiler knows you want an ulong, and thus the result of the shift operation is a positive long, which can be converted to an unlong - end error

    The correct reason why 1<<32 does not lead to compiler error is in the provided link to operator <<:

    If the first operand is an int, the shift count is given by the low-order five bits of the second operand. That is, the actual shift count is 0 to 31 bits.

    32 to binary: 0010 0000; low order five bits: 0 0000, So the actual performed shift is 1 << 0, which results to the int with the value 1, which of course can be assigned to an ulong.

    To solve this, make sure that your number 1 is a long. In that case 1<<31 is still a positive long.

    You can also use suffixes to specify the type of the literal according to the following rules: If you use L, the type of the literal integer will be either long or ulong according to its size.

    So 1L is a long; 1L <<31 is a positive long, and thus can be assigned to an ulong