2

My question is, within C++, is the following code defined? Some of it? And if it is, what's it supposed to do in these four scenarios?

word <<  100;
word >>  100;
word << -100;
word >> -100;

word is a uint32_t

(This is for a bottleneck in a 3d lighting renderer. One of the more minor improvements in the inner most loop I wanna make is eliminating needless conditional forks. One of those forks is checking to see if a left shift should be done on several 32 bit words as part of a hamming weight count. If the left shift accepts absurd values, the checks don't need done at all)

Anne Quinn
  • 12,609
  • 8
  • 54
  • 101

2 Answers2

11

In the C++0X draft N3290, §5.8:

The behavior is undefined if the right operand is negative, or greater than or equal to the length in bits of the promoted left operand.

Note: the above paragraph is identical in the C++03 standard.

So the last two are undefined. The others, I believe depend on whether word is signed or not, if word is at least 101bits long. If word is "smaller" than 101bits, the above applies and the behavior is undefined.

Here are the next two sections of that paragraph in C++0X (these do differ in C++03):

The value of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are zero-filled. If E1 has an unsigned type, the value of the result is E1 × 2E2 , reduced modulo one more than the maximum value representable in the result type. Otherwise, if E1 has a signed type and non-negative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a non-negative value, the value of the result is the integral part of the quotient of E1/2E2 . If E1 has a signed type and a negative value, the resulting value is implementation-defined.

Mat
  • 202,337
  • 40
  • 393
  • 406
  • 3
    If `word` is less than 100 bits in size then all four are undefined. – interjay Sep 25 '11 at 08:29
  • They're uint32_t, so unsigned all the way. So... according to that sentence, `word << 100` would be undefined because it's greater than 32 bits? Does being unsigned help it avoid that? – Anne Quinn Sep 25 '11 at 08:31
  • Oh, didn't see that edit in time. I'm not going to lie. That second paragraph's wording completely baffles me – Anne Quinn Sep 25 '11 at 08:33
  • @Clairvoire: just edited to make it clearer (I hope). The first paragraph is enough to rule out all four cases if `word` only has 32bits, as @interjay pointed out. – Mat Sep 25 '11 at 08:36
  • He didn't ask the c++0x question, therefore this answer is not correct – BЈовић Sep 25 '11 at 09:07
  • @VJo - How is answering with respect to the current standard not correct? – Mankarse Sep 25 '11 at 09:23
7

The C standard doesn't say what should happen when shift count is negative or greater than (or even equal) to the precision of the variable.

The reason is that the C standard didn't want to impose a behavior that would require extra code to be emitted in case of parametric shift. Since different CPUs do different things the standard says that anything can happen.

With x86 hardware the shift operator only uses last 5 bits of the shift counter to decide the shift amount (this can be seen by reading the CPU reference manual) so this is what most probably will happen with any C or C++ compiler on that platform.

See also this answer for a similar question.

Community
  • 1
  • 1
6502
  • 112,025
  • 15
  • 165
  • 265
  • Ah, that was pretty insightful, thank you~ I suppose if it were standard, it would have involved bounds checking anyway, so the penalty would have been there whether I had to write a check or not. – Anne Quinn Sep 25 '11 at 08:59
  • @Clairvoire: exactly. Requiring for example that `(x << count)` is the same as `(x >> -count)` would impose to compilers for x86 to generate test and branch code for every parametric shift because that's not what the hardware does. The choice instead was to leave it unspecified so the generated code will be as efficient as possible (just one machine instruction). If you need specified behavior for those cases then you can just write the code yourself. – 6502 Sep 25 '11 at 10:09