Reputation: 13195
Simple code snippet:
#define FOO 7
int bar = -875;
bar <<= FOO;
This is being reported by UBSAN as UB.
My understanding is that -875 << 7
is just -(875<<7)
and there is no overflow.
So, is there a real problem here?
Upvotes: 2
Views: 346
Reputation: 81247
On a sign-magnitude machine, it is unclear what the effect of left-shifting a negative number should be, and it would not be unreasonable for such a machine to trap if such an operation was attempted. On such a machine, imposing any requirements on the behavior of a negative integer left-shift would likely have required compilers for such machines to generate extra code even in cases where the values to be shifted would always be positive. To avoid imposing such costs, the authors of the Standard declined to mandate any particular behavior.
Ones'-complement and two's-complement platforms would have no logical reason to trap when shifting a negative value (though whether -1<<1 should yield -2 or -3 on a ones'-complement machine would be unclear), but the authors of the Standard saw no reason to say that left-shifting of negative values has Undefined Behavior on platforms which use sign-magnitude integers, Implementation-Defined Behavior on platforms that use ones'-complement, and Standard-defined behavior on platforms which use two's-complement, since any two's-complement implementation would regard -1<<1 as yielding -2, whether or not the Standard mandated it, unless the author was deliberately obtuse.
Until probably 2005 or so, there would have been nothing even imaginably unsafe about code which will only be called upon to run on commonplace two's-complement machines using the left-shift operator on a negative value. Unfortunately, around that time an idea started to take hold which suggested that a compiler which avoids doing anything the Standard doesn't mandate can be more "efficient" than one which behaves usefully in situations not mandated by the Standard, and that such "efficiency" is desirable. I am not yet aware of compilers regarding the statement y=x<<1;
as retroactively making the value of x non-negative, but I do not believe there is any reason to believe that they won't do so in future so unless or until some agency officially codifies the behavioral guarantees which mainstream microcomputer C compilers unanimously upheld for 25+ years such code cannot be considered "safe".
Upvotes: 3
Reputation: 320661
Your understanding is incorrect.
Firstly you used bar <<= FOO
syntax. This explicitly shifts bar
and bar
is negative. Left-shifting of negative values produces undefined behavior in C. There's no way bar <<= FOO
can be interpreted as -(875<<7)
.
Secondly, concerning -875 << 7
in terms of operator priority: unary operators always have higher priority than binary ones, which means that -875 << 7
is (-875) << 7
and not -(875 << 7)
. And, again, left-shifting of negative values produces undefined behavior in C.
Upvotes: 7