Question

If I read the C++ ISO specification (sections 5.8.2 and 5.8.3) right, the right-shift of negative signed types is implementation specific and the left-shift undefined behaviour.

Therefore I would like to find shift operations on signed types in our legacy source code which we compile with g++ 4.8.2.

Unfortunately, I couldn't find such an option in the manual. I can for example compile this code with "g++ -Wall -Wextra -pedantic" without a warning:

int si    = -1;
int left  = si << 1; // -2 (multiplication by 2, sign is preserved)
int right = si >> 1; // -1 (no change, only 1s)

Can anyone tell me if there is such a warning and, if not, why gcc doesn't care about it?

Was it helpful?

Solution

AFAIK gcc doesn't provide such an option. The standard, as you cited, says:

N3690 - §5.8.3

The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a non-negative value, the value of the result is the integral part of the quotient of E1/2E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.

and that means doing

int si    = -1;
int right = si >> 1;

might or might not yield -1 as a result. It's implementation defined. And that means the compiler is not forced to yield a warning like "other compilers might do this another way".

Some of the reasons for this choice follow.

The original K&R passage says:

"Right shifting an unsigned quantity, fills vacated bits with 0. Right shifting a signed quantity will fill with sign bits (arithmetic shift) on some machines such as the PDP-11, and with 0 bits (logical shift) on others."

this means that the operation is architecture-dependent. The reason behind this is that some architectures are fast in doing one of the two but not both.

This reason plus the fact that the usefulness of sign-extended shifts is marginal made the standard take the choice of leaving it "implementation defined". By "usefulness of sign-extended shifts" I mean that right shifting a negative signed integer arithmetically does not work as the positive counterpart (because losing a 1 on the right makes the negative number smaller, i.e. bigger in modulus)

+63 >> 1 = +31 (integral part of quotient E1/2E2)
00111111 >> 1 = 00011111
-63 >> 1 = -32 
11000001 >> 1 = 11100000

References for further reading:

https://stackoverflow.com/a/1857965/1938163

http://www.ccsinfo.com/forum/viewtopic.php?t=45711

https://isocpp.org/std/the-standard


Edit: if the above doesn't address the issue (i.e. the code is valid, why should a compiler warn about that?) I'm providing a second solution: AST matchers

As described here: http://eli.thegreenplace.net/2014/07/29/ast-matchers-and-clang-refactoring-tools/ you can write some code to identify quickly all the right-shifts-with-signed-integers spots in your program.

Think of it as "writing my small one-task static analysis checker".


Edit 2: you might also try other static-analysis tools, clang has a -fsanitize=shift option which could work for you. AFAIK also for gcc they were implementing an undefined behavior sanitizer which could help diagnosing those errors. I've not been following the story but I guess you could give it a try as well.

OTHER TIPS

The GCC documentation is here.

The answer appears to be "no", there's not any warning option for what you want.

I don't know why, but I'd guess that there's just so much code out there that uses this that it would be too noisy. C may not define arithmetic shifts, but pretty much all CPUs do it the same way, these days, so most people assume it is defined that way.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top