Error when trying to perform a bitwise not (~) on a UInt16 in C#

后端 未结 3 1830
醉酒成梦
醉酒成梦 2021-01-26 05:52

For some reason, I am simply not understanding (or seeing) why this works:

UInt32 a = 0x000000FF;
a &= ~(UInt32)0x00000001;

but this does n

相关标签:
3条回答
  • 2021-01-26 05:58

    Because §14.6.4 of the Standard (ISO 23270) says:

    14.6.4 Bitwise complement operator

    For an operation of the form ~x, unary operator overload resolution (§14.2.3) is applied to select a specific operator implementation. The operand is converted to the parameter type of the selected operator, and the type of the result is the return type of the operator. The predefined bitwise complement operators are:

    int operator ~(int x);
    uint operator ~(uint x);
    long operator ~(long x);
    ulong operator ~(ulong x);
    

    For each of these operators, the result of the operation is the bitwise complement of x.

    If you work through the unary operator overload resolution specified in §14.2.3, you'll find that, as noted by §14.2.6.1 ("Unary numeric promotions"), which is informative rather than normative, that the net effect is this:

    Unary numeric promotion occurs for the operands of the predefined +, , and ~ unary operators. Unary numeric promotion simply consists of converting operands of type sbyte, byte, short, ushort, or char to type int.

    So despite your cast, ~(ushort)0x0001, the compiler is smart enough to note the constant expression and do constant folding, meaning that the end result is a signed 32-bit integer with a value of -2, or 0xFFFFFFFE. And...

    Since the expression, a &= b ; is exactly equivalent to a = a & b ;, you are trying to do a bitwise AND of a ushort and an int. The ushort is upcast to an int and the bitwise AND evaluated, yielding a signed 32-bit integer result. . . . which can't be assigned to a ushort (unsigned 16-bit).

    That is why.

    0 讨论(0)
  • 2021-01-26 06:04

    Your expression evaluated at compile time and as result overflow error is detected and blocking compilation.

    Sample below show that run-time does not throw exception by default:

    UInt16 a = 0x00FF;
    UInt16 b = 0x0001;
    a &= (UInt16)~b; 
    

    Note that your code also was converting int (as result of ~ operation on UInt16 converted to int) - so I moved ~ before cast.

    Why: C# compiler generally tries to prevent unintentional code behavior if possible, which combined with all bit-wise operations defined on int/uint/long/ulong and compile time constant evaluation leads to this compile time error.

    0 讨论(0)
  • 2021-01-26 06:08

    The bitwise negation promotes the result to a int, despite the cast. You can overcome this by bitwise and-ing the result of the bitwise negation to the lower 16 bits, like this: ~0x0001 & 0xFFFF.

    0 讨论(0)
提交回复
热议问题