6

I am trying to clear the first nibble in a 16-bit unsigned integer (set it to 0).

One of the approaches I attempted was to use left bit shifting and then right bit shifting to clear the first four bits.

Here is my program.

#include <stdio.h>
#include <stdint.h>

int main() {
    uint16_t x = 0xabcd; // I want to print out "bcd"
    uint16_t a = (x << 4) >> 4;

    printf("After clearing first four bits: %x\n", a);

    return 0;
}

I am expecting the first bit shift (x << 4) to evaluate to 0xbcd0 and then the right bit shift to push a leading 0 in front - 0x0bcd. However, the actual output is 0xabcd.

What confuses me more is if I try to use the same approach to clear the last four bits,

uint16_t a = (x >> 4) << 4;

it works fine and I get expected output: abc0.

Why, in the program above, does the right bit shifting not push a leading 0?

vgru
  • 49,838
  • 16
  • 120
  • 201
  • 2
    Think of `(x << 4) >> 4` as an expression. Only limited by the architecture's (native) word size. [what ever that is] see: integer promotion rules. – wildplasser May 02 '19 at 23:09
  • Note: You are trying to clear the first nibble (or half-byte), not the first byte. – bitmask May 02 '19 at 23:13
  • On a 16-bit `int/unsigned` system, the result would be `0bcd` as expected. – chux - Reinstate Monica May 02 '19 at 23:18
  • 1
    there are a lot more duplicates although it's a bit hard to search [Bitshifting in C++ producing the wrong answer](https://stackoverflow.com/q/24100576/995714), [Why does combining two shifts of a uint8_t produce a different result?](https://stackoverflow.com/q/22702091/995714), [Unexepected behavior from multiple bitwise shifts on the same line](https://stackoverflow.com/q/25393058/995714), [Why does combining two shifts of a uint8_t produce a different result?](https://stackoverflow.com/q/22702091/995714) – phuclv May 03 '19 at 01:42
  • 1
    [Implicit type promotion rules](https://stackoverflow.com/questions/46073295/implicit-type-promotion-rules) – Lundin May 03 '19 at 09:23
  • 2
    So why not just `x & 0x0FFF`? – unalignedmemoryaccess May 03 '19 at 13:58

2 Answers2

9

Happens due to integer promotion. On systems where int is larger than 16 bits, your expression is converted to

uint16_t a = (int)((int)x << 4) >> 4;

and the upper bits are not stripped therefore.

ensc
  • 6,704
  • 14
  • 22
0

if you want to print out "bcd", maybe you can do like this:

#include <stdio.h>
#include <stdint.h>

int main() {
    uint16_t x = 0xabcd; // I want to print out "bcd"        // step 1
    uint16_t c = x << 4 ;                                    // step 2
    uint16_t a = c >> 4;                                     // step 3

    printf("After clearing first four bits: %x\n", a);

    return 0;
}

above output is :

After clearing first four bits: bcd

explanation:

when run step 1:

x is 1010101111001101 (binary)          // 1010(a) 1011(b) 1100(c) 1101(d)

go to step 2:

c is 1011110011010000 (binary)          // 1011(b) 1100(c) 1101(d) 0000(0)

finally go to step 3:

a is 101111001101 (binary)              // 1011(b) 1100(c) 1101(d)
Tom
  • 417
  • 3
  • 10