30

Normally, C requires that a binary operator's operands are promoted to the type of the higher-ranking operand. This can be exploited to avoid filling code with verbose casts, for example:

if (x-48U<10) ...
y = x+0ULL << 40;

etc.

However, I've found that, at least with gcc, this behavior does not work for bitshifts. I.e.

int x = 1;
unsigned long long y = x << 32ULL;

I would expect the type of the right-hand operand to cause the left-hand operand to be promoted to unsigned long long so that the shift succeeds. But instead, gcc prints a warning:

warning: left shift count >= width of type

Is gcc broken, or does the standard make some exception to the type promotion rules for bitshifts?

R.. GitHub STOP HELPING ICE
  • 195,354
  • 31
  • 331
  • 669
  • Will it promote anyway, regardless of the warning? (it is just a warning, after all). – Robert Harvey Aug 14 '10 at 06:14
  • 1
    Couldn't you just use a short macro to produce the verbose cast? Like `#define ULL(x) ((unsigned long long)x)`? – Borealid Aug 14 '10 at 06:16
  • 2
    @Robert: No, it produces a no-op, as if I had written plain `<<32`. @Borealid: Yes I could, but I like writing code that can be copy-and-pasted anywhere (e.g. other projects) without requiring extra defines/headers. I hate things like `typedef unsigned int uint;`. – R.. GitHub STOP HELPING ICE Aug 14 '10 at 06:21
  • 1
    @R..: About the typedef you've got there, see `stdint.h`. `uint64_t` is a 64-bit unsigned value. That's portable to most every platform. – Borealid Aug 14 '10 at 06:24
  • What typedef? You mean in my comment just above? It's there as an example of how I hate macros/typedefs used for shorthand, which require you to carry them along with every piece of code that uses the shorthand, not as an attempt to get a 64-bit type (which it obviously doesn't do on most platforms). – R.. GitHub STOP HELPING ICE Aug 14 '10 at 06:31
  • By the way, @Borealid, that's just as easily accomplished (as in my original statement of the question) with `x+0ULL` or `x*1ULL`, which don't depend on a macro being defined. Anyway, what I'd really like is an answer about whether this is a bug in gcc.. – R.. GitHub STOP HELPING ICE Aug 14 '10 at 06:33
  • 1
    @R.., I'm reasonably sure I just read something about this in the C99 rational document the other day. My recollection is that they deliberately chose to make the LHS participate in integer promotion, but not the RHS because the value on the RHS can only be as large as the number of bits in the type to its left without getting into undefined behavior. – RBerteig Aug 14 '10 at 07:16
  • and mark4o's answer confirms that my memory is plausible... – RBerteig Aug 14 '10 at 07:18

2 Answers2

35

The so-called usual arithmetic conversions apply to many binary operators, but not all of them. For example they do not apply to the bit shift operators, &&, ||, comma operator, and assignment operators. This is the rule for the bit shift operators:

6.5.7 ... 3 Semantics ...
The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand. If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.

jeb
  • 70,992
  • 15
  • 159
  • 202
mark4o
  • 52,963
  • 16
  • 81
  • 99
-1

The trouble really is that promotion only works up to whatever your platform defines as an int. As some other answers have stated, the bit-shift operator will promote the left operand to an int. However, here an int is defined as a 32-bit value. The integer conversion will not promote to a long long (64-bit).

Apriori
  • 2,222
  • 12
  • 15