Johnney
Johnney

Reputation: 147

Warning with my updated gcc compiler

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?

Upvotes: 1

Views: 1571

Answers (3)

ekchom
ekchom

Reputation: 148

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.

Upvotes: 1

Jonathan Leffler
Jonathan Leffler

Reputation: 754810

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
$

Upvotes: 4

Ulrich Eckhardt
Ulrich Eckhardt

Reputation: 17444

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.

Upvotes: 0

Related Questions