1

I have the following piece of code:

long int compute_data_length(unsigned char* buf, int data_offset) {

long int len;

if(!buf)
    return -1;

switch(data_offset) {
    case 2: {
                len = (buf[2] << 8) | buf[3];
            }
            break;
    case 8: {
                len = (buf[2] << 56) |
                      (buf[3] << 48) |
                      (buf[4] << 40) |
                      (buf[5] << 32) |
                      (buf[6] << 24) |
                      (buf[7] << 16) |
                      (buf[8] <<  8) |
                      (buf[9]      );
            }
            break;
    default: len = -1; break;
}
return len;
}

When I compile, I get the following warning:

math_fun.c:240:21: warning: left shift count >= width of type [enabled by default] len = (buf[2] << 56) | ^ math_fun.c:241:27: warning: left shift count >= width of type [enabled by default] (buf[3] << 48) | ^ math_fun.c:242:27: warning: left shift count >= width of type [enabled by default] (buf[4] << 40) | ^ math_fun.c:243:27: warning: left shift count >= width of type [enabled by default] (buf[5] << 32) |

How do I fix the warning?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
new_c_user
  • 123
  • 2
  • 12
  • 2
    How big is `long int`? Cast to the right type before doing the shifting. – Deduplicator Jun 23 '14 at 00:16
  • -bash-4.1$ ./a.out size of long int 8 long long 8 unsigned long 8 – new_c_user Jun 23 '14 at 00:19
  • Closely related to [Unsigned integer bit field shift yields signed integer](http://stackoverflow.com/questions/22152636/unsigned-integer-bit-field-shift-yields-signed-integer/22152886#22152886), on the fence whether it is a dup. – Shafik Yaghmour Jun 23 '14 at 01:41
  • Possible duplicate of [warning: left shift count >= width of type](https://stackoverflow.com/questions/4201301/warning-left-shift-count-width-of-type) – Evan Carroll Sep 18 '18 at 21:47

2 Answers2

5

Integer promotions turn buf[2] << 56 into (int)buf[2] << 56 [Note 1], but it is entirely possible that int only has 32 bits and you need it to be an unsigned 64-bit type for the shift to be meaningful.

You're expecting unsigned long to be 64 bits, but it might not be. It would be better to include <stdint.h> and use uint64_t. In any event, you need to explicitly cast the left operands of thE left shift:

((uint64_t)buf[2] << 56) | ...

[Note 1]: It's theoretically possible for unsigned char to be as wide as an int, in which case the integer promotion would be to an unsigned int. But that only happens on unusual architectures.

rici
  • 234,347
  • 28
  • 237
  • 341
  • 1
    A minor detail that doesn't really affect the quality of this answer, but `buf[2]` will be nearly always be promoted to `int`, not `unsigned int`. – Michael Burr Jun 23 '14 at 00:23
  • I don't think it's possible for `unsigned char` to be as wide as `int` in C99. The existence of `uint8_t` seems to imply that `unsigned char` is 8 bits wide, but `int` has to be more than that. – Tavian Barnes Jun 28 '14 at 02:04
  • 1
    @TavianBarnes: C99 standard, 7.20.1.1 (*Exact-width integer types*), para 3, emphasis added: "**These types are optional.** However, if an implementation provides integer types with widths of 8, 16, 32, or 64 bits, no padding bits, and (for the signed types) that have a two’s complement representation, it shall define the corresponding typedef names." – rici Jun 28 '14 at 02:56
0

Please learn to read warnings:

math_fun.c:240:21: warning: left shift count >= width of type [enabled by default] len = (buf[2] << 56) | ^

That gives you all the info you need to comprehend your error and how to remedy it:

The type you shift is less than 56 bits long, so shifting 56 bits or more is undefined behavior.
Cast to an appropriately bigger type first.

I hope long fits the bill on your platform, because that's the type of the variable you later assign the result to. int64_t would be guaranteed to be big enough, if it is provided.

While you are at it, consider using only unsigned types there, overflow on signed types is undefined.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118