0

I have probably a newby question about bitwise shifts in C. I wanted to write a macro, which will return a n-th bit of the unsigned char. My initial idea was to left shift by (7-n), bringing the bit to MSB position, and right shift by 7, bringing the bit to LSB. This didnt work, so I started with testing in non-macro enviroment.

So this doesnt work:

int main() {
    unsigned char c=126,d,i;
        
    for(i=0;i<8;++i){
        d = (c<<(7-i)) >> 7;
        printf("%d bit: %d\n",i,d);
    }
    return 0;
}

But this works:

int main() {
    unsigned char c=126,d,i;
        
    for(i=0;i<8;++i){
        d = (c<<(7-i));
        d >>= 7;
        printf("%d bit: %d\n",i,d);
    }
    return 0;
}

I solved the original problem with &mask.. d=(c>>i)&1;. However, I still dont understand why are those two different... Any ideas?

Ivan
  • 1
  • 2
  • See https://stackoverflow.com/questions/48775746/do-compilers-optimize-out-net-zero-bit-shifts – ocrdu Dec 03 '20 at 14:35
  • 2
    I believe this is due to integer promotions of bit shift operators and operands. Even though you have defined them as char, in example one, they are promoted and treated as integers; hence information is preserved. https://stackoverflow.com/questions/3482262/bitshift-and-integer-promotion – choppe Dec 03 '20 at 14:37
  • if you have an unsigned char d = 0 and want to set the n-th bit of it, like in x = 0010 0000, you have to logical OR it in, so in your macro, if you want the n-th bit, just XOR it out. if you XOR 0010 000, you get either 0 or 0010 0000, then you know whether the bit is set – clockw0rk Dec 03 '20 at 14:42
  • `d = (c<<(7-i)) >> 7;` This is the opposite shift direction than what you describe in your text. – Gerhardh Dec 03 '20 at 14:56

2 Answers2

0

With unsigned char c=126 and i==0:

(c<<(7-i)) is a 14-bit value.

d = (c<<(7-i)) >> 7; retains that 14-bit value then shifts right 7: information preserved.

d = (c<<(7-i)); d >>= 7; truncates that 14-bit value to 8-bits when saved into d, then shifts right: information lost.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Please pardon myself for the lack of understanding your answer, As per to the specification, I am not able to conclude that this is the right answer to the question; Although it has been accepted as the right answer. My confusion again is validated from the discussion on following stack-overflow thread. Any clarification would benfit my own growth as an Engineer. https://stackoverflow.com/questions/3482262/bitshift-and-integer-promotion – choppe Dec 03 '20 at 14:55
  • @choppe Is it clear the 1) 126 is a 7-bit value and `(c<<(7-i))` is a 14-bit value? – chux - Reinstate Monica Dec 04 '20 at 03:02
  • The size of the value depends on register size associated to each architecture. 14-bit value is misleading the reader, this was my point. plus the cause is associated to the integer promotion on bit-wise operators. – choppe Dec 16 '20 at 15:33
  • @choppe Still hoping for answers to prior [comment](https://stackoverflow.com/questions/65127673/c-and-bitwise-shifts/65127892?noredirect=1#comment115157284_65127892). The allowable shift range depends on the type, in this case, the sizeof an `int` which is at least 16-bit. It is not dependent on the architecture register size, although the native size influences `int` size. The `int` size is at least 16-bit, even when the native register size is smaller. The `int` size may even be less than the native register size as is many times the case with 64-bit machines. – chux - Reinstate Monica Dec 16 '20 at 16:31
  • Thanks chux, my point was that 14-bit value is misleading in some manner. Thanks again for your response! – choppe Dec 16 '20 at 20:14
0

The correct way to get bit number n is val & (1u << n). With a macro this would be:

#define BIT(val, n) ( (val) & (1u << (n)) )

If you want 1 or 0 then just (bool)BIT(0x80, 7); etc.


Though generally, please refrain from inventing macros like this since val & (1u << n) is already the most readable, canonical form.

This u8 = val & (1u << 7); is far superior to u8 = BIT(val,7);.

Lundin
  • 195,001
  • 40
  • 254
  • 396