2

I am using the following code to sign extend a 12 bit value I unpacked from 1.5 bytes to 16 bits:

word[0] |= ((word[0] & 0x800) != 0 ? (Int16)(-4096) : (Int16)0);

If I don't cast the last zero to Int16 I get the following complaints from the compiler:

Warning 1   Bitwise-or operator used on a sign-extended operand; consider casting to a smaller unsigned type first
Error   2   Cannot implicitly convert type 'int' to 'short'. An explicit conversion exists (are you missing a cast?)

Why is this? I understand that C# converts everything to an int when doing bitwise operations, but normally integer constants are automatically given the right type. If I assign zero to a float I don't have to cast it to float first, for example. I'm a C programmer, so please keep that in mind when answering :-)

1 Answers1

0

The only types of integer literals in C# are for the types int, uint, long, and ulong (C# Language specification, version 5, section 2.4.4.2). Any literal (such as 0) will only have its type inferred as one of those 4 (and without any extra indications, it's an int).

So, why does:

short s = 0;

work? That would be due to Implicit constant expression conversions (section 6.1.9):

A constant-expression (§7.19) of type int can be converted to type sbyte, byte, short, ushort, uint, or ulong, provided the value of the constant-expression is within the range of the destination type.

But, what we're working with here isn't a constant expression. So all of the conventional C# typing rules come into play; When analyzing the conditional operator (section 7.14), the types are:

bool ? short : int;

And the compiler (without being able to use the above constant-expression rule) decides that the type of that expression is int, since a short may be implicitly converted to an int, but not vice-versa.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • Okay, but can you explain why C# doesn't support literal shorts? What is the point of making you cast literals when the compiler can easily check that they fit into a short? I understand what it is doing, I want to know why. Also, you say that the expression isn't constant, but I'm not clear what part you are referring to. –  Apr 14 '14 at 10:01
  • @MoJo - I think that they believed that the *constant-expression* rule would be sufficient for most cases (as, in my answer, a direct assignment of a literal `int` to a `short` variable). They could have supported more types of literals (e.g. `0s` maybe, for a `short` literal) but they didn't. Since I didn't participate in any language design meetings, I can't offer a *defitinive* "why". – Damien_The_Unbeliever Apr 14 '14 at 10:04
  • @MoJo - re: the constant expression, I agree that I've not highlighted it too well in my answer. But basically, it's when we're considering the entire conditional operator (`?:`) - because the *condition* (`(word[0] & 0x800) != 0`) isn't a constant, the entire expression isn't a constant. If we write `short s = false? 0 : 1;`, the conditional operator itself is a constant expression (of type `int`) and so that, again, compiles because of the above rule. – Damien_The_Unbeliever Apr 14 '14 at 10:09
  • @MoJo - finally, if you want to find out more about constant expressions, there's a full section (7.19, referenced in the above quote) that discusses what constant expressions are. – Damien_The_Unbeliever Apr 14 '14 at 10:11
  • Thanks Damien. I see what you mean now, the conditional operator makes the zero conditional as well even though it is a compile-time constant and would be treated as such in C. So if I used an if() statement instead would the assignment in that be considered conditional or constant? –  Apr 14 '14 at 12:56