What aspects of signed left shift are undefined with GCC?

C99 §6.5.7/3-4 lists two specific undefined behaviors regarding the left shift operator (<<):

3) [...] If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.

4) The result of E1 << E2 is [...]. 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.

How exactly GCC behaves in these circumstances, I can't say. It's perfectly welcome to give defined behavior in these situations; however, such code will still be undefined when compiled with other compilers.

My guess is that GCC treats signed left shifting identically to unsigned left shifting—that is, if computes x << y as (signed)((unsigned)x << y) by doing the bit shifts (potentially discarding any upper bits), and then reinterpreting the result as a signed quantity. This has the implication that the most-significant value bit of a signed integer gets shifted into the sign bit; that seems a little strange from an arithmetic perspective but makes perfect sense from a bitwise perspective.


The informations on the left shift operator in C99 draft standard (ISO/IEC9899:TC3, aka WG14/N1256) are rather scant.

Section 6.5.7 (bitwise shift operators) has already been cited by Alter Mann.

Annex J, section J.2 (Undefined behavior) says the following:

The behavior is undefined in the following circumstances:
[...]

— An expression is shifted by a negative number or by an amount greater than or equal to the width of the promoted expression (6.5.7).

— An expression having signed promoted type is left-shifted and either the value of the expression is negative or the result of shifting would be not be representable in the promoted type (6.5.7).

I don't think it is allowed for a conforming implementation to make some mandatory undefined behavior defined. If I'm not mistaken an implementation is allowed to define unspecified behavior (but it is not required to) and is required to specify implementation defined behavior, but undefined behavior cannot be specified. This doesn't mean that an implementation cannot choose a sane meaningful behavior, but it cannot let the user rely on that (it cannot "specify it").

I admit I'm not completely sure of that. Hope this helps.

Edit: Upon further reflection I think a conforming implementation can specify a behavior for what the standard deems undefined behavior, but the resulting program cannot be called conforming (see section 3.4.3).


Other answers have already pointed out which aspects of << are undefined behavior. My guess is that you want a "translation" of the gcc into common language.

If a behavior is undefined by the C standard, compiler implementors can take the "latitude" to do anything that suits them if such a case occurs. In particular, they don't have to implement a diagnostic or detection of that case, and may pretend that it never happens. It is the responsability of the programmer to write his program such that its behavior is always defined.

In the case of left shift, this means that a compiler would not have to check for overflow and can pretend that a loop like

for (int i = 1; i > 0; i <<= a) {
 .... change a in some complicated way ...
}

would never terminate.

The sentence that you are citing indicates that they don't do such a thing, yet, but that future versions of gcc might do so.

Tags:

C

Bit Shift

Gcc