What does the compiler do here: int a = b * (c * d * + e)?

C++Arithmetic Expressions

C++ Problem Overview


I had a strange bug in my program, and after a few hours of debugging, I found the following very stupid line:

int a = b * (c * d *  + e)

If you don't see it: Between d and e I wrote * +, where just a +was intended.

Why does this compile and what does it actually mean?

C++ Solutions


Solution 1 - C++

The + is interpreted as an unary plus operator. It simply returns the promoted value of its operand.

Solution 2 - C++

Unary + returns the promoted value.
Unary - returns the negation:

int a = 5;
int b = 6;
unsigned int c = 3;

std::cout << (a * +b); // = 30
std::cout << (a * -b); // = -30
std::cout << (1 * -c); // = 4294967293 (2^32 - 3)

Solution 3 - C++

This compiles because the + is being interpreted as unary plus, which will perform the integral promotions on integral or enumeration types and the result will have the type of the promoted operand.

Assuming e is an integral or unscoped enumeration type would end up having the integral promotions applied anyway since * applies the usual arithmetic conversions to its operands which ends up at the integral promotions for integral types.

From the draft C++ standard 5.3.1 [expr.unary.op]:

>The operand of the unary + operator shall have arithmetic, unscoped enumeration, or pointer type and the result is the value of the argument. Integral promotion is performed on integral or enumeration operands. The type of the result is the type of the promoted operand.

The integral promotions are covered in section 4.5 [conv.prom] and if the variables e is a type other than bool, char16_t, char32_t, or wchar_t and have conversion rank less than int then it would be covered by paragraph 1:

>A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int.

For a complete set of cases we can look at cppreference.

Unary plus can also be useful in some cases to resolve ambiguity, an interesting case would be from Resolving ambiguous overload on function pointer and std::function for a lambda using +.

Note, for those answers, referring to unary - and negative values, this is misleading, as this example shows:

#include <iostream>

int main()
{
    unsigned  x1 = 1 ;

    std::cout <<  -x1 << std::endl ;
}

which results in:

4294967295

See it live using gcc on wandbox.

It is interesting to note that unary plus was added to C99 for symmetry with unary minus, from the Rationale for International Standard—Programming Languages—C:

>Unary plus was adopted by the C89 Committee from several implementations, for symmetry with unary minus.

and I can not come up with a good case where casting would not be sufficient to achieve the same desired promotion/conversion. The lambda example I cite above, using unary plus to force a lambda expression to be converted to a function pointer:

foo( +[](){} ); // not ambiguous (calls the function pointer overload)

could be accomplished using a explicit cast:

foo( static_cast<void (*)()>( [](){} ) );

and it could be argued this code is better since the intention is explicit.

Worth noting that Annotated C++ Reference Manual(ARM) it has the following commentary:

>Unary plus is a historical accident and generally useless.

Solution 4 - C++

As what they have explained, (+) and (-) were just used as unary operator:

> Unary operators act on only one operand in an expression

int value = 6;
int negativeInt = -5;
int positiveInt = +5;

cout << (value * negativeInt); // 6 * -5 = -30
cout << (value * positiveInt); // 6 * +5 = 30

cout << (value * - negativeInt); // 6 * -(-5) = 30
cout << (value * + negativeInt); // 6 * +(-5) = -30

cout << (value * - positiveInt); // 6 * -(+5) = -30
cout << (value * + positiveInt); // 6 * +(+5) = 30

so from your code:

int b = 2;
int c = 3;
int d = 4;
int e = 5;

int a = b * (c * d *  + e)

//result: 2 * (3 * 4 * (+5) ) = 120

Solution 5 - C++

Why does it compile? It compiles because + is parsed as unary plus operator, not the addition operator. The compiler tries to parse as much as possible without generating syntax errors. So this:

d * + e

Is parsed as:

  • d (operand)
  • * (multiplication operator)
  • + (unary plus operator)
    • e (operand)

Whereas, this:

d*++e;

Is parsed as:

  • d (operand)
  • * (multiplication operator)
  • ++ (pre increment operator)
    • e (operand)

Moreover, this:

d*+++e;

Is parsed as:

  • d (operand)
  • * (multiplication operator)
  • ++ (pre increment operator)
    • + (unary plus operator)
      • e (operand)

Note that it does not create a syntax error but the "LValue requrired" compiler error.

Solution 6 - C++

To put a further twist on the correct answers already given here, if you compile with the -s flag, the C compiler will output an assembly file in which actual the instructions generated can be examined. With the following C code:

int b=1, c=2, d=3, e=4;
int a = b * (c * d *  + e);

The generated assembly (using gcc, compiling for amd64) begins with:

    movl    $1, -20(%ebp)
    movl    $2, -16(%ebp)
    movl    $3, -12(%ebp)
    movl    $4, -8(%ebp)

so we can identify individual memory positions -20(%ebp) as variable b, down to -8(%ebp) as variable e. -4(%epp) is variable a. Now, the calculation is rendered as:

    movl    -16(%ebp), %eax
    imull   -12(%ebp), %eax
    imull   -8(%ebp), %eax
    imull   -20(%ebp), %eax
    movl    %eax, -4(%ebp)

So, as has been commented by other people replying, the compiler simply treats "+e" as the unary positive operation. The first movl instruction places the contents of variable e into the EAX accumulator register, which is then promptly multiplied by the contents of variable d or -12(%ebp), etc.

Solution 7 - C++

This is just basic math. For example:

5 * -4 = -20

5 * +4 = 5 * 4 = 20 

-5 * -4 = 20

Negative * Negative = Positive

Positive * Negative = Negative

Positive * Positive = Positive

This is the easiest explanation there is.

The minus(-) and plus(+) just tell if the number is positive or negative.

Solution 8 - C++

The + operator between d and e will be treated as an unary + operator which will determine only sign of e. So the compiler will see this statement as follow:

int a = b*(c*d*e) ;

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMichaelView Question on Stackoverflow
Solution 1 - C++Brian BiView Answer on Stackoverflow
Solution 2 - C++Andreas DMView Answer on Stackoverflow
Solution 3 - C++Shafik YaghmourView Answer on Stackoverflow
Solution 4 - C++Dyrandz FamadorView Answer on Stackoverflow
Solution 5 - C++Salman AView Answer on Stackoverflow
Solution 6 - C++ALAN WARDView Answer on Stackoverflow
Solution 7 - C++LokoView Answer on Stackoverflow
Solution 8 - C++nitish-dView Answer on Stackoverflow