0

Take the following code snippet:

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

void decodeStatus(uint8_t d)
{
    uint64_t a = d << 31;
    uint64_t b = d << 32;
}

When shifting an uint8_t eight or more places to the left, it becomes 0, which results in a warning. The compiler is obligated to make sure that an uint8_t is exactly 8 bits (C11 spec 7.20.1.1 sections 1 & 2), so that both shifts should result in a warning. But apparently, only the second shift creates a warning:

gcc -c main.c -o a.out
main.c: In function ‘decodeStatus’:
main.c:7:20: warning: left shift count >= width of type [-Wshift-count-overflow]
         uint64_t b = d << 4*8;

Is this a compiler bug, or is there a logical explanation? I verified this on the following compilers:

$> gcc --version
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
$> arm-linux-gnueabihf-gcc --version
arm-linux-gnueabihf-gcc (GCC) 9.2.0
Cheiron
  • 3,620
  • 4
  • 32
  • 63
  • 1
    `buf[x]` gets promoted to `int`, which is often 32bits nowadays. Search for "usual arithmetic conversions" – Mat Mar 12 '20 at 15:23

1 Answers1

0

You need to cast the shifted data

uint64_t decodeStatus(uint8_t* buf)
{
    uint64_t raw = (uint64_t)buf[0] | ((uint64_t)buf[1] << (1*8))
        | ((uint64_t)buf[2] << (2*8)) | ((uint64_t)buf[3] << (3*8))
        | ((uint64_t)buf[4] << (4*8)) | ((uint64_t)buf[5] << (5*8))
        | ((uint64_t)buf[6] << (6*8)) | ((uint64_t)buf[7] << (7*8));
}
0___________
  • 60,014
  • 4
  • 34
  • 74