0

Given a Byte (e.g. 0x49), i want to change the high-nibble from 4 to 7.

That is:

0x490x79

I've tried the following:

Byte b = 0x49;
b = 0x70 | (b & 0x0f);

But it fails to compile:

Compilation error: Cannot implicitly convert type 'int' to 'byte'. An explicit conversion exists (are you missing a cast?)

What am i doing wrong?

CMRE

using System;

public class Program
{
    public static void Main()
    {
        //The goal is to change the high nibble of 0x49 from 4 to 7.  That is 0x49 ==> 0x79
        Byte b = 0x49;
        b = b & 0x0f;
        b = 0x70 | b;
        Console.WriteLine(b.ToString());
    }
}

https://dotnetfiddle.net/V3bplL

I've tried casting every piece i can find as (Byte), but it still complains. And rather than firing a hard-cast cannon at the code, and hoping something sticks, i figured i would get the correct answer.

That's why the example code contains no (Byte) casts:

  • it shouldn't be needed
  • i want someone else to explain to me exactly where, and exactly why, it or they is or are needed

Hence the easy to click dotnetfiddle link. People can try it for themselves, add a (Byte) cast, see it fails to compile, go "Huh", and try adding more casts randomly.

For those who didn't read

For the pedants who didn't bother to try it:

Byte b = (Byte)0x49;
b = ((Byte)0x70) | ((Byte)(((Byte)b) & ((Byte)((Byte)0x0f))));

also fails.

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
  • 1
    What about adding a cast? – Progman May 06 '20 at 19:22
  • @Progman Do you think adding a cast will help? What about six? – Ian Boyd May 06 '20 at 19:26
  • There's no byte literal suffix, hence why it's interpreted as int. You need the cast. https://stackoverflow.com/questions/5378036/literal-suffix-for-byte-in-net – Dean Goodman May 06 '20 at 19:26
  • 4
    See [OR-ing bytes in C# gives int](https://stackoverflow.com/questions/1214629/or-ing-bytes-in-c-sharp-gives-int) and [Why do C#'s binary operators always return int regardless of the format of their inputs?](https://stackoverflow.com/questions/3079986/why-do-cs-binary-operators-always-return-int-regardless-of-the-format-of-their) – dxiv May 06 '20 at 19:28
  • @DeanGoodman That's correct but it's not the whole story. Just `b = b & b;` would trigger the same error. – dxiv May 06 '20 at 19:29

1 Answers1

2

Bit manipulating a Byte returns an Int32:

  • Byte & ByteInt32
  • Byte | ByteInt32

So you need to cast in order to not have your intermediate expressions be interpreted as an int:

Byte b = 0x49;
b = (Byte)(b & 0x0f);
b = (Byte)(0x70 | b);

Or simply:

Byte b = 0x49;
b = (Byte)(0x70 | (b & 0x0f));
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
Dean Goodman
  • 973
  • 9
  • 22
  • That's very odd. Why is it that adding casts does not work here? `b = ((Byte)0x70) | ((Byte)(((Byte)b) & ((Byte)((Byte)0x0f))));` – Ian Boyd May 06 '20 at 19:30
  • 1
    In that case you aren't casting the overall expression: `b = (byte) (0x70 | (byte)(b & 0x0f))`. – mr_greb May 06 '20 at 19:30
  • 1
    @gbishop3 Ahhh! The lack of a literal `Byte` suffix is a red-herring. The real issue is that `byte | byte` results in an `int`! That makes perfect sense in C#. – Ian Boyd May 06 '20 at 19:32
  • Maybe not quite a red-herring - I'd expect if there *was* such a suffix that `0x70x | b` (where x is our fictional suffix) *would* in fact evaluate to a `Byte`. That's my expectation of a language feature that doesn't exist, so your point about `byte | byte` resulting in `int` is taken as it's the reality of the language today. – Dean Goodman May 06 '20 at 19:35
  • Over [here](https://stackoverflow.com/a/3079999/12597) they talk about how it's because `Byte` has no `&` operator defined; so the values have to be promoted to `int`. And then you need to manually throw away the upper 16-bits. Tedious; very tedious. – Ian Boyd May 06 '20 at 19:40