30

How does the following code work and what do the variables mean:

y = (x << shift) | (x >> (sizeof(x)*CHAR_BIT - shift));

I found in a circular shift article but with no explanation on how this works.

rudolph9
  • 8,021
  • 9
  • 50
  • 80
user1809300
  • 703
  • 4
  • 9
  • 17

4 Answers4

35

This is a method of doing a circular shift. Suppose that x is 8 bits.

+----+----+----+----+----+----+----+----+
| x1   x2   x3   x4   x5   x6   x7   x8 |
+----+----+----+----+----+----+----+----+

Then, shifting it left by 3 gives us:

+----+----+----+----+----+----+----+----+
| x4   x5   x6   x7   x8    0    0    0 |
+----+----+----+----+----+----+----+----+

Now, CHAR_BIT*sizeof(x) is the same as the width of x in bits, 8. So shifting x to the right by 8 - 3 gives us:

+----+----+----+----+----+----+----+----+
| 0    0    0    0    0    x1   x2   x3 |
+----+----+----+----+----+----+----+----+

And taking the OR you get:

+----+----+----+----+----+----+----+----+
| x4   x5   x6   x7   x8   x1   x2   x3 |
+----+----+----+----+----+----+----+----+

It is called a circular shift or "rotation" because the bits that get shifted out on the left get shifted back in on the right.

This code can actually invoke undefined behavior if one of the shifts is equal to or larger than the width of the promoted type. Fortunately, there’s an easy fix…

y = (x << shift) |
    (x >> ((sizeof(x) * CHAR_BIT - shift) %
           (sizeof(x) * CHAR_BIT)));

Sophisticated compilers will actually compile the code down to a hardware rotation instruction. For example,

#include <limits.h>
unsigned rotate(unsigned x, unsigned shift) {
    return (x << shift) |
        (x >> ((sizeof(x) * CHAR_BIT - shift) %
               (sizeof(x) * CHAR_BIT)));
}

On Godbolt, you can try this out and see the generated code. At -O with GCC 12 on x86, the result is rol:

rotate:
        mov     eax, edi
        mov     ecx, esi
        rol     eax, cl
        ret
Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • 4
    +1, but 8 is not a good example of amount by which it is undefined to shift, because per usual arithmetic conversions, the shifted type is at least (signed or unsigned) `int`, and `int` is at least 16 bits. – Pascal Cuoq Nov 08 '12 at 13:49
  • Very good explanation, but I am facing a problem while doing bit-wise left shift. The compiler seems to take the bits in group of 32 but I need to work only on 8 bits while doing the cyclic left shift. This means `1111 0000` when shifted to left by 1 should give `1110 0001` instead of `1111 00000` as it gives now by the compiler. Can you help? – sudoCoder Apr 18 '20 at 17:47
26

CHAR_BIT is the number of bits per byte, should be 8 always.

shift is the number of bits you want to shift left in a circular fashion, so the bits that get shifted out left, come back on the right.

     1110 0000 << 2 results in:
     1000 0011

code for the example:

   y = (x << 2) | (x >> (8 - 2));
thumbmunkeys
  • 20,606
  • 8
  • 62
  • 110
  • and if i want to cirlular shift a number with a bitstream of 10 digits ex 1111101010 then CHAR_BIT is 10 or i am wrong? – user1809300 Nov 08 '12 at 12:55
  • 5
    CHAR_BIT is always 8 for any sane architecture you'll use in the 21st century :-) – xanatos Nov 08 '12 at 12:57
  • 2
    @PascalCuoq `x >> 8 - 2` is parsed as `x >> (8 - 2)` with a warning: **operator '>>' has lower precedence than '-'; '-' will be evaluated first [-Wshift-op-parentheses]** – fujianjin6471 Jan 31 '16 at 03:30
  • 1
    @fujianjin6471 Indeed. I have deleted my comment, but I would say it is as well the parentheses stay in the answer, seeing how the people less familiar with C get confused otherwise. – Pascal Cuoq Jan 31 '16 at 03:37
7
(x << shift) 

Shifts it 'shift' number of bits to the left, returns the shifted out bits

(x >> (sizeof(x)*CHAR_BIT - shift));

Makes space for accommodating those bits

CHAR_BIT is the number of bits in char, so is 8 mostly. In C, you don't handle one bit at a time, but at a minimum, char number of bits. So that is the granularity you get.

In general,

For a char, when you do a bit-rotate, you would do it on an 8-bit field (1 byte)

For an int, when you do a rotate, you would do it on a 32-bit field (4 bytes)


Example with 8 bits:

x = 11010101
shift = 2

x << (shift) = 01010100 //shifted left by 2 bits

= x >> ((1 * CHAR_BIT) - shift)
= x >> (6) 
= 00000011 //shifted right by 6bits

OR these bit-wise to give

01010100 //x << 2
00000011 //x >> 6
________
01010111

That is the circular shifted value by 2 bits

Community
  • 1
  • 1
Anirudh Ramanathan
  • 46,179
  • 22
  • 132
  • 191
2

This works with unsigned types only. In the case with a signed negative number most left bits will be substituted by the value of most significant bit (with 1-s) by the right-shift operator (">>")

I'd write it like this:

y = (x << shift) | ( (x >> (sizeof(x)*CHAR_BIT - shift)) & (0x7F >> (sizeof(x)*CHAR_BIT - shift) );

In here before "|" operator we do confirm that first n bits ( n = sizeof(x)*CHAR_BIT - shift) are zeroed. We also assume, that x is short (2-bytes long). So, it's also type-dependent.

Xentatt
  • 1,264
  • 22
  • 35