C# int byte conversion

65,953

Solution 1

Surprisingly, when you perform operations on bytes the computations will be done using int values, with the bytes implicitly cast to (int) first. This is true for shorts as well, and similarly floats are up-converted to double when doing floating-point arithmetic.

The second snippet is equivalent to:

byte someVar;
someVar = (int) someVar - 3;

Because of this you must cast the result back to (byte) to get the compiler to accept the assignment.

someVar = (byte) (someVar - 3);

Solution 2

Here's a copy of a table in the CLI specification (Ecma 335) that specifies which operands are valid on the binary numeric operators of the type A op B, where A and B are the operands and "op" is the operator, like Opcodes.Sub that you are using in your snippet:

alt text

Some annotations are required with this:

  • "native int" is IntPtr in a C# program
  • F represents a floating point type, double or float in C#
  • & represents a pointer value, the boxes are shaded because they are unsafe operations
  • O represents an object reference
  • x is an operation that's not permitted.

Note the row and column for F, both operands must be floating point, you cannot directly add, say, an int to a double. The C# compiler deals with that limitation by automatically converting the int operand to double so that the operator is valid.

Relevant to your question: also note that the byte, sbyte, char, short and ushort types are not present. Same approach, the compiler converts the operands to the smallest type that can represent the value so that the operator can be used. Which will be int32. According to the table, the result of the operation will be int32.

Now here's the rub: the result is int32 but assigning that back to a byte value requires a narrowing conversion. From 32 bits to 8 bits. That's trouble because it loses significant bits. The C# compiler requires you to make that explicit. You essentially acknowledge that you know what you're doing and that you are aware of the potentially surprising result. Like this one:

byte v = 255;
v = (byte)(v + 1);

The -= operator is a problem because there is no effective way to apply that required cast. It isn't expressible in the language syntax. Using (byte)3 doesn't make sense, the literal gets converted to int32 anyway to make the operator work.

They punted the problem, the compiler automatically emits the cast without your help.

Share:
65,953
BTHarris
Author by

BTHarris

Seasoned C#/Javascript Developer Im always working on something. github Contact me for more information. (Dested at Gmail)

Updated on December 15, 2020

Comments

  • BTHarris
    BTHarris over 3 years

    Why is

    byte someVar;
    someVar -= 3; 
    

    valid but

    byte someVar;
    someVar = someVar - 3;
    

    isnt?

  • BTHarris
    BTHarris almost 14 years
    Can someone verify if the type casting happens at the IL level in the someVar-=3; example? Does it generate the same IL code?
  • Thomas Levesque
    Thomas Levesque almost 14 years
    I just checked with Reflector. The -= operator generates a conv.u1 at the IL level, which is why the first snippet is working
  • Jeppe Stig Nielsen
    Jeppe Stig Nielsen over 11 years
    @Dested The precise rules are given in the C# Language Specification. It states: "The second rule above permits x op= y to be evaluated as x = (T)(x op y) in certain contexts. The rule exists such that the predefined operators can be used as compound operators when the left operand is of type sbyte, byte, short, ushort, or char. Even when both arguments are of one of those types, the predefined operators produce a result of type int, as described in §7.3.6.2. Thus, without a cast it would not be possible to assign the result to the left operand."
  • fusi
    fusi almost 9 years
    this explains why i am unable to use reflection to implicitly cast between types.