Integral promotion: It doesn’t have to be logical. It’s the law.

Integral promotion is one of those things that everybody takes for granted, but most people don’t know exactly how or when, or what it does exactly.

Simply said, integral promotion means that an integer type can automatically be widened to a wider type. For example, in the following statement, b is automatically widened to a short because a is also of that type.

  short a;

  char b = 2;
  a = b;

Everybody assumes this will happen because it is the logical thing to do.

What most people don’t realize is that integral promotion is not something that happens when it is logical. It happens when the C or C++ standard says it should happen.

Every once and again, someone posts a message in the public VC++ forums or newsgroups about how he found a bug in the VC++ compiler for the following code (it’s nearly always the same code).

  short a = 1;

  short b = 2;
  a += b;

This example will cause a warning at warning level /W4: warning C4244: ‘+=’ : conversion from ‘int’ to ‘short’, possible loss of data.

There is even a bug logged at connect about this behavior, and it’s gotten good feedback because a lot of people really think this is a bug, but it’s not.

The C++ standard says that the result of += is subject to the integral promotion rules that will promote narrow integer values to proper ints. So even though a and b are both of type short, the results of += is of type int. when that is assigned to a the compiler recognizes that you are assigning an int to a short and generates the appropriate warning.

Integral promotion happens for the result of several operators. The one that triggered this blog post is the unary + operator.

For those who don’t know what it does: it returns the value of whatever is on the right hand side. You can use it like in the following contrived example.

  short a = 1;  short b;

  b = +a;

The funny thing is that the result of the unary plus is also subject to integral promotion. The result of +a is of type int, so it should also generate warning C4244. Actually, that is not entirely correct. According to the language lawyers in comp.lang.c++, the compiler is not required to generate a warning. However, if it generates a warning for 1 case (+=) it should logically also generate a warning for the other cases.

So I logged a bug on connect. I am not sure that it’ll get much attention, and I even hesitated to put it in. But perhaps this is a very simple fix, and if more C4244 warnings are given, then perhaps more people will learn and understand the integral promotion rules.

Some links to documentation for promotion rules:

Standard C++ conversions explained in MSDN

C++ arithmetic conversions in MSDN

C type conversions in MSDN

Usual arithmetic conversions (C) in MSDN


Btw, you might think that the unary + is a completely useless language feature, but I got a couple of use cases on comp.lang.c++ that convinced me otherwise:

  1. Kai-Uwe Bux: One thing that comes to mind is that it renders expression like  + some_var + some_other_var + yet_another_var legal. This can come in handy when you want to generate code mechanically

  2. James Kanze: I suspect that there’s an orthogonality issue involved.  It would seem rather odd to have unary minus, but not unary plus.

  3. James Kanze: In another thread, Alf used +0 to force a char to be treated as an int—unary plus would work as well (and be even more obfuscation), e.g.:
    char c = ‘a’ ;
    std::cout << +c << std::endl ;
    will display “97” on my machine, whereas without the +, it displays “a” (but I still prefer “(int)( c )”).

  4. Ben Pfaff: In C, sometimes the unary plus operator is used to keep an expression from being an lvalue.  For example:
    struct opaque { int foo; };
    #define foo_accessor(OPAQUE) (+(OPAQUE)->foo)
    Without the +, the foo_accessor macro could be used to set the value of `foo’, as in foo_accessor(x) = 0;
    With the +, the above will not compile

Leave a Reply

Your email address will not be published. Required fields are marked *