9

When I compile the following code with gcc :

int main()
{
  unsigned char c = 1;
  c <<= 1;  // WARNING ON THIS LINE
  return 0;
}

I get this warning :

conversion to ‘unsigned char’ from ‘int’ may alter its value [-Wconversion]

Why ? What is wrong with this code ? Actually, can I really use the oprator <<= on a unsigned char variable ?

Compilation command :

g++ test.cpp -Wconversion -o test.exe

Caduchon
  • 4,574
  • 4
  • 26
  • 67
  • 1
    This, it seems to me, is one of those "damned if you do and damned if you don't" situations, for both compiler writers and users. As a user, what you wrote is clean and produces the intended answer and is generally entirely unexceptionable. And it doesn't need extra linguistic clutter to make it harder to understand. As a compiler writer, there is technically a narrowing conversion, so the warning is technically correct. But I can't help but feel that in this context, or the analogous ones involving `short` (which presumably also trigger the warning), the warning is really not constructive. – Jonathan Leffler Apr 22 '15 at 13:40

1 Answers1

8

This is a valid warning:

c <<= 1;

is equivalent to:

c = c << 1

and the rules for << say that the operands are promoted and in this case will be promoted to int and the result is of the promoted type. So there will be a conversion from int to unsigned char at the end which may result in an altered value.

The code is valid, the warning is telling you that an implicit conversion is happening and in some cases the conversion could alter the value. Using a cast will silence the warning. Results of implicit conversions can be very counter-intuitive and in some cases undefined behavior. See the gcc Wconversion wiki for some details.

I don't see a way to remove the warning without expanding the operation out manually and using static_cast:

c = static_cast<unsigned char>( c << 1 );

As we can see from the long thread on this gcc bug report not everyone feels that this is a useful case for this warning.

For reference from the draft C++ standard section 5.8 Shift operators:

The operands shall be of integral or unscoped enumeration type and integral promotions are performed. The type of the result is that of the promoted left operand [...]

and from section 5.17 Assignment and compound assignment operators:

The behavior of an expression of the form E1 op = E2 is equivalent to E1 = E1 op E2 except that E1 is evaluated only once. [...]

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 1
    I also have the problem if a do `c <<= static_cast(1);`. Are you then saying there is no shift operator for 1 byte types in C++ ? :-/ – Caduchon Apr 22 '15 at 11:50
  • 4
    See [Why must a short be converted to an int before arithmetic operations in C and C++?](http://stackoverflow.com/q/24371868/1708801) for a rationale on why operands are promoted to wider types. Mostly because it results in faster generated code. – Shafik Yaghmour Apr 22 '15 at 11:52
  • It seems it finally was accepted as a bug, and now it's fixed in gcc 10.0 – Rom098 Oct 08 '20 at 13:09