C# Bitwise OR needs casting with byte *sometimes*
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.
Related videos on Youtube
Nate
I'm a developer with broad experience and a curious disposition. I like learning about and creating new things.
Updated on April 16, 2022Comments
-
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 over 14 yearsI did not know there was a |=. Thanks!
-
Nate over 14 yearsYeah, I changed my post after I realized that. Thanks.
-
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 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 abyte
is an int. -
Godeke over 14 yearsThe 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 over 14 years
x |= y
andx &= ~y
are your friends for bit manipulation. -
Godeke over 14 yearsEMCA-334 14.10 Logical Operators
-
Roman Starkov over 13 yearsUnfortunately 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)