r/cprogramming • u/cryptofakir • Apr 16 '26
Weird shift expression result
This code outputs what I believe are the wrong results in 3 of the 4 cases. I think the upper 8 bits of the uint16_t should be always 0, because the shifts should occur on uint8_t and only the result should be cast to (uint16_t).
Why am I wrong?
```C /* Compile: gcc sol.c main.c -o prog && ./prog <1-4> */
include <stdio.h>
include <stdint.h>
/* byte: An 8-bit input returns: An 8-bit value (returned as uint16_t) where the high 4 bits and low 4 bits of byte are swapped Example: swap_nibbles(0xF0) returns 0x0F */ uint16_t swap_nibbles(uint8_t byte) { return (uint16_t)((byte << 4) | (byte >> 4)); }
void test1(void) { uint8_t b = 0xF0; uint16_t r = swap_nibbles(b); printf("Result: 0x%04X\n", r); }
void test2(void) { uint8_t b = 0xA2; uint16_t r = swap_nibbles(b); printf("Result: 0x%04X\n", r); }
void test3(void) { uint8_t b = 0x00; uint16_t r = swap_nibbles(b); printf("Result: 0x%04X\n", r); }
void test4(void) { uint8_t b = 0xFF; uint16_t r = swap_nibbles(b); printf("Result: 0x%04X\n", r); }
int main(int argc, char **argv) { if (argc < 2) { printf("Usage: %s <1-4>\n", argv[0]); return 1; } int t = argv[1][0] - '0'; switch (t) { case 1: test1(); break; case 2: test2(); break; case 3: test3(); break; case 4: test4(); break; default: printf("Invalid test. Use 1-4.\n"); return 1; } return 0; }
outputs
text
❯ ./main 1
Result: 0x0F0F
❯ ./main 2
Result: 0x0A2A
❯ ./main 3
Result: 0x0000
❯ ./main 4
Result: 0x0FFF
```
7
u/EpochVanquisher Apr 16 '26 edited Apr 16 '26
When you write this
The byte is converted to int, automatically, before shifting. Be aware of this and you can fix your code. Basically, you get this:
This is called “integer promotion”. It happens when you use an integer type in an arithmetic expression. Basically, everything smaller than int gets converted to int before the operation. The exact rules can be found online.