74

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?

8
  • 1
    Uses: stackoverflow.com/a/3182557/962089 In addition, there's printing (or otherwise using) the integral value of a character type: std::cout << +c; If this happens a lot, static_cast gets very cluttery. Commented May 20, 2015 at 22:17
  • 4
    Hint: what if you had intended to write a minus? Commented May 21, 2015 at 1:05
  • What if the type of e? Commented May 21, 2015 at 2:15
  • 1
    What does 2 × (3 × 4 × +5) do in normal arithmetic? Commented May 21, 2015 at 16:06
  • 2
    @Boann I think the question isn't as trivial as all that. Not all "basic math notations" work in programming. We all know that thinking in terms of math when programming is a recipe for disaster. Commented May 21, 2015 at 20:42

8 Answers 8

119

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

Sign up to request clarification or add additional context in comments.

2 Comments

For more detail on "promoted", see here
The effect of this is identical to int a = b * (c * d * (+e))
27

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) 

3 Comments

"Positive value" is misleading. That makes it sound like it returns the absolute value of the operand, which is not the case.
Nor does - necessarily return "the negative value": int b = -5; std::cout << -b;
@MSalters thank you, corrected the wording
18

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.

Comments

9

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 

Comments

5

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.

Comments

4

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.

Comments

3

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.

2 Comments

it's not like that, how about this: int a = -5; int val = -a; //result val: 5
--5 becomes 4 :p -(-5) = 5..just kidding i know it's just a typo.. yeah you're right :) +1
-1

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) ; 

2 Comments

"which will determine only sign of e" How so?
I meant to say that + sign will work as +5 ,iff e=5..like that.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.