Is It Legal to Use the Increment Operator in a C++ Function Call

Is it legal to use the increment operator in a C++ function call?

Quoth the C++ standard 1.9.16:

When calling a function (whether or
not the function is inline), every
value computation and side effect
associated with any argument
expression, or with the postfix
expression designating the called
function, is sequenced before
execution of every expression or
statement in the body of the called
function. (Note: Value computations
and side effects associated with the
different argument expressions are
unsequenced.)

So it would seem to me that this code:

foo(i++);

is perfectly legal. It will increment i and then call foo with the previous value of i. However, this code:

foo(i++, i++);

yields undefined behavior because paragraph 1.9.16 also says:

If a side effect on a scalar object is
unsequenced relative to either another
side effect on the same scalar object
or a value computation using the value
of the same scalar object, the
behavior is undefined.

Why are these constructs using pre and post-increment undefined behavior?

C has the concept of undefined behavior, i.e. some language constructs are syntactically valid but you can't predict the behavior when the code is run.

As far as I know, the standard doesn't explicitly say why the concept of undefined behavior exists. In my mind, it's simply because the language designers wanted there to be some leeway in the semantics, instead of i.e. requiring that all implementations handle integer overflow in the exact same way, which would very likely impose serious performance costs, they just left the behavior undefined so that if you write code that causes integer overflow, anything can happen.

So, with that in mind, why are these "issues"? The language clearly says that certain things lead to undefined behavior. There is no problem, there is no "should" involved. If the undefined behavior changes when one of the involved variables is declared volatile, that doesn't prove or change anything. It is undefined; you cannot reason about the behavior.

Your most interesting-looking example, the one with

u = (u++);

is a text-book example of undefined behavior (see Wikipedia's entry on sequence points).

C Operator Precedence postfix increment and dereference

As you have correctly assumed, the expression *p++ is evaluated as *(p++); that is, the ++ operator has higher precedence than the * operator.

However, the value of the expression, p++, is just the value of p (i.e. its value before the increment). A side-effect of the operation is that the value of p is incremented after its value has been acquired.

From this Draft C11 Standard:

6.5.2.4 Postfix increment and decrement operators



2     The result of the postfix ++ operator is the
value of the operand. As a side effect, the value of the operand
object is incremented (that is, the value 1 of the appropriate type is
added to it). … The value computation of the result is sequenced
before the side effect of updating the stored value of the operand. With
respect to an indeterminately-sequenced function call, the operation of
postfix ++ is a single evaluation. …

Is there a performance difference between i++ and ++i in C++?

[Executive Summary: Use ++i if you don't have a specific reason to use i++.]

For C++, the answer is a bit more complicated.

If i is a simple type (not an instance of a C++ class), then the answer given for C ("No there is no performance difference") holds, since the compiler is generating the code.

However, if i is an instance of a C++ class, then i++ and ++i are making calls to one of the operator++ functions. Here's a standard pair of these functions:

Foo& Foo::operator++()   // called for ++i
{
this->data += 1;
return *this;
}

Foo Foo::operator++(int ignored_dummy_value) // called for i++
{
Foo tmp(*this); // variable "tmp" cannot be optimized away by the compiler
++(*this);
return tmp;
}

Since the compiler isn't generating code, but just calling an operator++ function, there is no way to optimize away the tmp variable and its associated copy constructor. If the copy constructor is expensive, then this can have a significant performance impact.

What is the difference between ++i and i++?

  • ++i will increment the value of i, and then return the incremented value.

     i = 1;
    j = ++i;
    (i is 2, j is 2)
  • i++ will increment the value of i, but return the original value that i held before being incremented.

     i = 1;
    j = i++;
    (i is 2, j is 1)

For a for loop, either works. ++i seems more common, perhaps because that is what is used in K&R.

In any case, follow the guideline "prefer ++i over i++" and you won't go wrong.

There's a couple of comments regarding the efficiency of ++i and i++. In any non-student-project compiler, there will be no performance difference. You can verify this by looking at the generated code, which will be identical.

The efficiency question is interesting... here's my attempt at an answer:
Is there a performance difference between i++ and ++i in C?

As @OnFreund notes, it's different for a C++ object, since operator++() is a function and the compiler can't know to optimize away the creation of a temporary object to hold the intermediate value.

Why avoid increment (++) and decrement (--) operators in JavaScript?

My view is to always use ++ and -- by themselves on a single line, as in:

i++;
array[i] = foo;

instead of

array[++i] = foo;

Anything beyond that can be confusing to some programmers and is just not worth it in my view. For loops are an exception, as the use of the increment operator is idiomatic and thus always clear.

Why are multiple increments/decrements valid in C++ but not in C?

In C the result of the prefix and postfix increment/decrement operators is not an lvalue.

In C++ the result of the postfix increment/decrement operator is also not an lvalue but the result of the prefix increment/decrement operator is an lvalue.

Now doing something like (++a)-- in C++ is undefined behavior because you are modifying an object value twice between two sequence points.

EDIT: following up on @bames53 comment. It is undefined behavior in C++98/C++03 but the changes in C++11 on the idea of sequence points now makes this expression defined.

Incrementing in C++ - When to use x++ or ++x?

It's not a question of preference, but of logic.

x++ increments the value of variable x after processing the current statement.

++x increments the value of variable x before processing the current statement.

So just decide on the logic you write.

x += ++i will increment i and add i+1 to x.
x += i++ will add i to x, then increment i.

Behaviour of increment and decrement operators in Python

++ is not an operator. It is two + operators. The + operator is the identity operator, which does nothing. (Clarification: the + and - unary operators only work on numbers, but I presume that you wouldn't expect a hypothetical ++ operator to work on strings.)

++count

Parses as

+(+count)

Which translates to

count

You have to use the slightly longer += operator to do what you want to do:

count += 1

I suspect the ++ and -- operators were left out for consistency and simplicity. I don't know the exact argument Guido van Rossum gave for the decision, but I can imagine a few arguments:

  • Simpler parsing. Technically, parsing ++count is ambiguous, as it could be +, +, count (two unary + operators) just as easily as it could be ++, count (one unary ++ operator). It's not a significant syntactic ambiguity, but it does exist.
  • Simpler language. ++ is nothing more than a synonym for += 1. It was a shorthand invented because C compilers were stupid and didn't know how to optimize a += 1 into the inc instruction most computers have. In this day of optimizing compilers and bytecode interpreted languages, adding operators to a language to allow programmers to optimize their code is usually frowned upon, especially in a language like Python that is designed to be consistent and readable.
  • Confusing side-effects. One common newbie error in languages with ++ operators is mixing up the differences (both in precedence and in return value) between the pre- and post-increment/decrement operators, and Python likes to eliminate language "gotcha"-s. The precedence issues of pre-/post-increment in C are pretty hairy, and incredibly easy to mess up.


Related Topics



Leave a reply



Submit