1

Getting this warning with my new gcc compiler 6.X version.

warning: result of '117901309 << 24' requires 52 bits to represent,
but 'int' only has 32 bits [-Wshift-overflow=]

I have defined a macro with #define CLON 0x070707FD in my code which converts to decimal value shown above in the warning.

It seems like int is taking 4 bytes as I am running on a 64-bit machine. But I'm not sure how it went fine on earlier gcc version, say 4.X version. Can any one please help me understanding this?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Johnney
  • 127
  • 1
  • 9
  • 2
    Your new compiler has implemented better warnings/more checks and finds new (potential) bugs in your code. That's expected. – Mat Jan 09 '18 at 06:54
  • I honestly don't understand what your reference to `CLON` is supposed to express, so I ignored it in the answer below. It shouldn't matter what you used that code for. In any case, it would have been good to provide a simple but complete example for the code causing a warning instead of just code fragments that can be interpreted differently. – Ulrich Eckhardt Jan 09 '18 at 06:58
  • `int` actually only got 31 value bits which you can left shift through. If it had 32 bits it would be unsigned and then the warning wouldn't make any sense. Bad warning, gcc... – Lundin Jan 09 '18 at 08:43

3 Answers3

4

The new compiler is warning you about undefined behaviour which the old compiler did not warn you about. Be grateful, and finish your upgrade by moving to GCC 7.2.0, which is the latest GA version of GCC.

The C11 standard §6.5.7 Bitwise shift operators says:

The result of E1 << E2 is E1 left-shifted E2 bit positions; vacated bits are filled with zeros. If E1 has an unsigned type, the value of the result is E1 × 2E2, reduced modulo one more than the maximum value representable in the result type. If E1 has a signed type and nonnegative value, and E1 × 2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.

Since your result requires 52-bits, it is not representable in a 32-bit signed integer, and the compiler is correctly warning you that you're invoking undefined behaviour — which is something you should avoid doing.

There are many ways of fixing the problem, but perhaps this is the simplest fix — change the type of CLON to unsigned with the U suffix (or you could use UL or even ULL if you really wanted unsigned long or unsigned long long results):

#define CLON 0x070707FD
#define ULON 0x070707FDU

int shift_CLON(void);
unsigned shift_ULON(void);

int shift_CLON(void)
{
    return CLON << 24;
}

unsigned shift_ULON(void)
{
    return ULON << 24;
}

When that code is in a file sw73.c, you can compile it like so:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
>     -Wstrict-prototypes -c sw73.c
sw73.c: In function ‘shift_CLON’:
sw73.c:9:17: error: result of ‘117901309 << 24’ requires 52 bits to represent, but ‘int’ only has 32 bits [-Werror=shift-overflow=]
     return CLON << 24;
                 ^~
cc1: all warnings being treated as errors
$
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • There's also `UINT64_C(0x070707FD)` – M.M Jan 09 '18 at 07:58
  • Yes, indeed, there are a number of variations like that. And the value could be assigned to an appropriate (unsigned) variable and shifted, and … There are lots of circumventions; they all hinge on making the operand to the shift into an unsigned type so that the result is defined. (My answer left out a function using a cast — `unsigned shift_unsigned(void) { return (unsigned)CLON << 24; }` — which is what I wrote first to demonstrate to myself that using unsigned values was the key to resolving the issue.) – Jonathan Leffler Jan 09 '18 at 08:01
1

You need to specify explicit size to be used. You need to define the macro as

#define CLON 0x070707FDU

Or

#define CLON 0x070707FDL

You may refer to ULL suffix on a numeric literal.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
ekchom
  • 113
  • 13
  • 1
    Note that using the `L` suffix alone only works on 64-bit Unix platforms; it won't work on 64-bit Windows (because `sizeof(long) == 4` there), nor will it work on 32-bit systems. Use `U`, `UL` or `ULL` — the key component being the `U`. – Jonathan Leffler Jan 09 '18 at 07:39
0

The size of an int is indeed compiler/system-dependent. However, that is nothing new, so odds are that with earlier versions the code didn't do what you expect already, only that with newer versions it also issues a warning.

In order to fix that, consider using explicit bit sizes on the constant, like e.g. 117901309ll. Which of the several ones is appropriate here depends on your use case, in any case I'd consider using an unsigned value, too.

Ulrich Eckhardt
  • 16,572
  • 3
  • 28
  • 55