views:

164

answers:

3

Hi All,

I'm trying to reverse the order of bits in C (homework question, subject: bitwise operators). I found this solution, but I'm a little confused by the hex values (?) used -- 0x01 and 0x80.

  unsigned char reverse(unsigned char c) {
     int shift;
     unsigned char result = 0;

     for (shift = 0; shift < CHAR_BITS; shift++) {
        if (c & (0x01 << shift))
            result |= (0x80 >> shift);
     }
     return result;
  }

The book I'm working out of hasn't discussed these kinds of values, so I'm not really sure what to make of them. Can somebody shed some light on this solution? Thank you!

+3  A: 

0x01 is the least significant bit set, hence the decimal value is 1.

0x80 is the most significant bit of an 8-bit byte set. If it is stored in a signed char (on a machine that uses 2's-complement notation - as most machines you are likely to come across will), it is the most negative value (decimal -128); in an unsigned char, is is decimal +128.

The other pattern that becomes second nature is 0xFF with all bits set; this is decimal -1 for signed characters and 255 for unsigned characters. And, of course, there's 0x00 or zero with no bits set.

What the loop does on the first cycle is check if the LSB (least significant bit) is set, and if it is, sets the MSB (most significant bit) in the result. On the next cycle, it checks the next to LSB and sets the next to MSB, etc.

| MSB |     |     |     |     |     |     | LSB |
|  1  |  0  |  1  |  1  |  0  |  0  |  1  |  1  |   Input
|  1  |  1  |  0  |  0  |  1  |  1  |  0  |  1  |   Output
|  1  |  0  |  0  |  0  |  0  |  0  |  0  |  0  |   0x80
|  0  |  0  |  0  |  0  |  0  |  0  |  0  |  1  |   0x01
|  0  |  1  |  0  |  0  |  0  |  0  |  0  |  0  |   (0x80 >> 1)
|  0  |  0  |  0  |  0  |  0  |  0  |  1  |  0  |   (0x01 << 1)
Jonathan Leffler
Careful. The negative values are only valid for for twos-complement representation of integers. In ones-complement or sign-magnitude the bit-patterns have different meanings. C doesn't mandate the use of twos-complement.
Steve Emmerson
@Steve: true enough...I've adjusted the answer accordingly.
Jonathan Leffler
Wow. Thank you for the explanation -- the illustration really locked it in for me.
ajax81
A: 
Jon Purdy
Sixteens place? Do you want to fix that or explain that?
Jonathan Leffler
If you look at each nybble as a digit in the base-16 representation of the number, then 8 is in the sixteens place. But I doubt this will relieve the OPs confusion.
GregS
+1  A: 

Each hex digit represents 4bits, so

  • 0x01 is just a long way of writing 1.
  • 0x80 is a short way of writing in binary [1000][0000], or 128.

The solution is using bitwise operators to test and set values.

The expression:

if (a & b) { ... }

executes '...' if the same bit is 1 in both 'a' and 'b'.

The expression

c |= b

sets the bits in 'c' to 1, if they are 1 in 'b'.

The loop moves the test & set bit down the line.

Good luck!

Stephen