Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Bitwise OR needs casting with byte *sometimes* [duplicate]

I found an odd situation in the C# compiler. Why the cast below is required?

using System;

class Program
{
    private const byte BIT_ZERO_SET = 1;
    private const byte BIT_ONE_SET = 2;
    private const byte BIT_TWO_SET = 4;

    static void Main(string[] args)
    {
        byte b = BIT_ZERO_SET | BIT_ONE_SET;
        Console.WriteLine(b);

        //Does not compile, says needs to cast to int.
        //b = b | BIT_TWO_SET;

        //Compiles...ugly
        b = (byte)(b | BIT_TWO_SET);
        Console.WriteLine(b);

        Console.WriteLine("Press enter.");
        Console.ReadLine();    
    }
}

Thanks.

like image 468
Nate Avatar asked Oct 14 '09 18:10

Nate


3 Answers

The various answers here are generally correct, but have a bunch of different facts spread out all over the place. The relevant points are:

1) The result of byte | byte is an int, because there is no | operator defined on bytes.

2) Computations involving only integral compile-time constants are treated as "checked" arithmetic; that is, the compiler verifies that the constant result does not overflow, and so on. A pleasant consequence of this fact is that an assignment of a compile-time constant integer to a variable or constant of a smaller type automatically verifies that the constant integer fits into the smaller type. If it does, then the assignment is allowed without an explicit cast. If it does not, then a compile-time error occurs. (Use the "unchecked" expression if you want to override this behaviour.)

3) Assignments from non-constant expressions of type int to byte require casts, because the compiler has no way of knowing that the result definitely fits in the byte.

4) The compound assignment operators automatically insert a cast to the operand type as part of their operation, precisely so that expressions like b |= whatever work as you'd expect.

Those four facts should explain all the behaviour that you guys have pointed out.

like image 111
Eric Lippert Avatar answered Oct 13 '22 22:10

Eric Lippert


Is suspect that the line:

byte b = BIT_ZERO_SET | BIT_ONE_SET;

is actually processed by the C# compiler into an assignment of a constant value to b, rather than a bitwise operation - it can do this because the right side of the expression is fully defined at compile time.

The line:

//b = b | BIT_TWO_SET;

doesn't compiled because the bit-wise OR operator promotes its elements and evaluates to an int, not a byte. Since it involves a runtime value (b) it cannot be compiled into a constant assignment like the line before, and requires casting.

like image 24
LBushkin Avatar answered Oct 13 '22 21:10

LBushkin


It is definitely strange, but what is happening, is the result of b|BIT_TWO_SET is an integer.

this works: b = (byte)(b | BIT_TWO_SET); because the result is an int in that case.

Also, you could replace that line with : b |= BIT_TWO_SET; which works.

like image 24
Erich Avatar answered Oct 13 '22 23:10

Erich