1

I am messing around with c#, and i noticed something. If i were to instantiate an sbyte with 8 bits, such as 0b_1111_1111 (-1), it throws an error, but if i were to first make a byte with it, and then cast it, it now works.

//Method 1
sbyte test = 0b_1111_1111; //(-1)fails on run
//Method 2
sbyte test = (sbyte)0b_1111_1111; //(-1)also fails on run
//Method 3
byte temp = 0b_1111_1111; //currently 255
sbyte test = (sbyte)temp; //(-1) no issues now
Console.WriteLine(test); // writes -1

I am confused on why this happens, as methods 2 and 3 are nearly identical, and the only difference is that i made a variable to then be cast. Why does this happen?

1
  • 2
    You say "fails on run" but it's actually a compiler error so it doesn't even compile dotnetfiddle.net/Mbl7WM Commented Sep 7 at 0:33

2 Answers 2

7

These are compiler errors, not runtime errors. You are not allowed to assign a constant integer that is too large in a checked context.

Binary numbers starting 0b is just another way of writing a number. So 0b_1111_1111 is just 255 and you can't write sbyte test = 255; either.

What does work, but looks a bit weird, is:

sbyte test = -0b_0000_0001;

which is the same as:

sbyte test = -1;

Note that the negation is inlined by the compiler.

The benefit of writing binary numbers isn't really useful here, which is why most people would probably just follow what the compiler tells them and add unchecked.

sbyte test = unchecked((sbyte)0b_1111_1111);

As noted in the spec:

For constant expressions (§12.23) (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked. Unless a constant expression is explicitly placed in an unchecked context, overflows that occur during the compile-time evaluation of the expression always cause compile-time errors.

Sign up to request clarification or add additional context in comments.

Comments

6

If I were to instantiate an sbyte with 8 bits

This is your misconception - the literal 0b_1111_1111 does not represent "8 bits". Integer literals always numbers. 0b_1111_1111 represents the numerical value of 255, exactly the same value as the literal 255. You are effectively writing

sbyte test = 255;

255 is larger than sbyte.MaxValue (127), so this does not compile.

To write the numerical value of -1 using a binary integer literal, you can write

sbyte test = -0b1;

(sbyte)0b_1111_1111 also does not compile, because 0b_1111_1111 is a constant expression. Conversions involving constant expressions are checked by default. On the other hand, a variable name such as temp is not a constant expression, and conversions involving those are unchecked by default. From the spec:

For non-constant expressions (§12.23) (expressions that are evaluated at run-time) that are not enclosed by any checked or unchecked operators or statements, the default overflow checking context is unchecked, unless external factors (such as compiler switches and execution environment configuration) call for checked evaluation.

For constant expressions (§12.23) (expressions that can be fully evaluated at compile-time), the default overflow checking context is always checked. Unless a constant expression is explicitly placed in an unchecked context, overflows that occur during the compile-time evaluation of the expression always cause compile-time errors.

You can write

sbyte x = unchecked((sbyte)0b1111_1111);

like the spec suggests, or use CreateTruncating, which I find easier to read, though this incurs the overhead of calling a method.

sbyte x = sbyte.CreateTruncating(0b_1111_1111);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.