C# Bitwise OR needs casting with byte *sometimes*

14,551

Solution 1

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.

Solution 2

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.

Solution 3

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.

Solution 4

        b = (byte)(b | BIT_TWO_SET);

is all you need to cast to make it compile, at least in Visual Studio 2008 against 2.0. It appears that | promotes the byte to int and you have to demote it again by hand.

Yep... a quick run past the standard shows that | returns int (or uint or long or ulong).

Solution 5

Instead of using

 b = b | BIT_TWO_SET;

use this:

 b |= BIT_TWO_SET;

funny huh.

Share:
14,551

Related videos on Youtube

Nate
Author by

Nate

I'm a developer with broad experience and a curious disposition. I like learning about and creating new things.

Updated on April 16, 2022

Comments

  • Nate
    Nate about 2 years

    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.

  • Nate
    Nate over 14 years
    I did not know there was a |=. Thanks!
  • Nate
    Nate over 14 years
    Yeah, I changed my post after I realized that. Thanks.
  • Henk Holterman
    Henk Holterman over 14 years
    +1, Yes, the compiler will compute constant expressions at compile time. Which explains why the 1st assignment does not give an error.
  • Adam Robinson
    Adam Robinson over 14 years
    @Godeke: How are you saying anything different than he is? He's saying that the resulting value of a bitwise OR on a byte is an int.
  • Godeke
    Godeke over 14 years
    The whole constant expression thing is a red herring, that's all. | will never return a byte without casting, it only returns int, uint, long or ulong.
  • Christian Hayter
    Christian Hayter over 14 years
    x |= y and x &= ~y are your friends for bit manipulation.
  • Godeke
    Godeke over 14 years
    EMCA-334 14.10 Logical Operators
  • Roman Starkov
    Roman Starkov over 13 years
    Unfortunately the same trick can't be used for unsetting bits, because that requires a ~BIT_TWO_SET. This doesn't even work for constants, whether signed or unsigned (because of the specifics of the implicit cast rules)