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?

Assem
  • 11,574
  • 5
  • 59
  • 97
Michael
  • 7,407
  • 8
  • 41
  • 84
  • 1
    Uses: http://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. – chris May 20 '15 at 22:17
  • 4
    Hint: what if you had intended to write a minus? – geometrian May 21 '15 at 01:05
  • What if the type of `e`? – Shafik Yaghmour May 21 '15 at 02:15
  • 1
    What does `2 × (3 × 4 × +5)` do in normal arithmetic? – Jon Hanna May 21 '15 at 16:06
  • This isn't a question about programming so much as it's a question about reading basic math notation. – Boann May 21 '15 at 17:20
  • 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. – Atsby May 21 '15 at 20:42
  • @ShafikYaghmour and I've seen, as I've already told y'all, *dozens* of them, most of them concerning C#/Java/JS/Python, but a couple of them also mentioning C directly. see http://stackoverflow.com/questions/6637005/what-is-the-purpose-of-the-unary-operator-in-c - would that Q/A fit your "exact duplicate", or do I have to dig through http://stackoverflow.com/search?page=2&tab=relevance&q=unary%20plus further? believe me or not, this **has** been asked before... **dozens** of times in **dozens** of flavours. –  May 22 '15 at 17:25
  • @vaxquis that one is actually much better but it is marked as `C` and since this one already has C++ specific answers we should not change this tag. – Shafik Yaghmour May 23 '15 at 10:25

8 Answers8

119

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

Community
  • 1
  • 1
Brian Bi
  • 111,498
  • 10
  • 176
  • 312
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)
Andreas DM
  • 10,685
  • 6
  • 35
  • 62
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.

Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
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
Dyrandz Famador
  • 4,499
  • 5
  • 25
  • 40
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.

Salman A
  • 262,204
  • 82
  • 430
  • 521
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.

ALAN WARD
  • 1,072
  • 9
  • 4
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.

Loko
  • 6,539
  • 14
  • 50
  • 78
-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) ;
nitish-d
  • 241
  • 2
  • 11