Take the 2-minute tour ×

Possible Duplicate:

Here is a test case:

void foo(int i, int j)
test = 0;
foo(test++, test);

I would expect to get a "0 1" output, but I get "0 0" What gives??

share|improve this question
Perhaps your description/example should fully include the title question? –  Kris Kumler Sep 19 '08 at 0:18
The title and the code example are mismatched –  itj Sep 19 '08 at 8:02
Question is confused between the title and the code example. title has ++n example has test++ –  itj Sep 19 '08 at 8:05
add comment

marked as duplicate by Vlad Lazarenko, Pieter van Ginkel, Josh Caswell, j0k, Monolo Sep 10 '12 at 7:39


10 Answers

This is not just unspecified behaviour, it is actually undefined behaviour .

Yes, the order of argument evaluation is unspecified, but it is undefined to both read and modify a single variable without an intervening sequence point unless the read is solely for the purpose of computing the new value. There is no sequence point between the evaluations of function arguments, so f(test,test++) is undefined behaviour: test is being read for one argument and modified for the other. If you move the modification into a function then you're fine:

int preincrement(int* p)
    return ++(*p);

int test;
printf("%d %d\n",preincrement(&test),test);

This is because there is a sequence point on entry and exit to preincrement, so the call must be evaluated either before or after the simple read. Now the order is just unspecified.

Note also that the comma operator provides a sequence point, so

int dummy;

is fine --- the increment happens before the read, so dummy is set to the new value.

share|improve this answer
For prosperity, I think it worth while adding the standard reference for these. ISO C++ 5p4. –  Richard Corden Sep 19 '08 at 11:23
Don't you mean posterity? Or do you mean to help make programmers more wealthy? –  James A. Rosen Oct 21 '08 at 14:22
@Anthony, i think you missed the parens around the initializer of dummy :) –  Johannes Schaub - litb Oct 6 '09 at 13:15
add comment
up vote 47 down vote accepted

This is an example of unspecified behavior. The standard does not say what order arguments should be evaluated in. This is a compiler implementation decision. The compiler is free to evaluate the arguments to the function in any order.

In this case, it looks like actually processes the arguments right to left instead of the expected left to right.

In general, doing side-effects in arguments is bad programming practice.

Instead of foo(test++, test); you should write foo(test, test+1); test++;

It would be semantically equivalent to what you are trying to accomplish.

Edit: As Anthony correctly points out, it is undefined to both read and modify a single variable without an intervening sequence point. So in this case, the behavior is indeed undefined. So the compiler is free to generate whatever code it wants.

share|improve this answer
As added emphasis, to avoid these sorts of problems I always have increments as a separate statement. –  David L Morris Sep 19 '08 at 1:17
I wouldn't emphasize that. Maybe if you're new to the language you may want to take it slow, but this syntax exists for a reason, and it's not only because i += 1 is 3 more characters. –  Loren Segal Sep 19 '08 at 3:47
Is it just me or the evaluation order for operands has nothing to do with what you see? test++ is post increment, so test is incremented after being passed, as Mike Thompson says below. –  agnul Sep 19 '08 at 14:39
If I use (++t, t), I'm not sure if would be evaluated after. THAT would be wrong semantically, as it should be incremented BEFORE the function call i.e. bar(++t) IS valid. with bar(t++), I say "use t then increment" –  Benoit Sep 19 '08 at 14:49
add comment

To repeat what others have said, this is not unspecified behavior, but rather undefined. This program can legally output anything or nothing, leave n at any value, or send insulting email to your boss.

As a matter of practice, compiler writers will usually just do what's easiest for them to write, which generally means that the program will fetch n once or twice, call the function, and increment sometime. This, like any other conceivable behavior, is just fine according to the standard. There is no reason to expect the same behavior between compilers, or versions, or with different compiler options. There is no reason why two different but similar-looking examples in the same program have to be compiled consistently, although that's the way I'd bet.

In short, don't do this. Test it under different circumstances if you're curious, but don't pretend that there is a single correct or even predictable result.

share|improve this answer
add comment

Everything I said originally is WRONG! The point in time at which the side-affect is calculated is unspecified. Visual C++ will perform the increment after the call to foo() if test is a local variable, but if test is declared as static or global it will be incremented before the call to foo() and produce different results, although the final value of test will be correct.

The increment should really be done in a separate statement after the call to foo(). Even if the behaviour was specified in the C/C++ standard it would be confusing. You would think that C++ compilers would flag this as a potential error.

Here is a good description of sequence points and unspecified behaviour.


The "++" bit of "test++" gets executed after the call to foo. So you pass in (0,0) to foo, not (1,0)

Here is the assembler output from Visual Studio 2002:

mov	ecx, DWORD PTR _i$[ebp]
push	ecx
mov	edx, DWORD PTR tv66[ebp]
push	edx
call	_foo
add	esp, 8
mov	eax, DWORD PTR _i$[ebp]
add	eax, 1
mov	DWORD PTR _i$[ebp], eax

The increment is done AFTER the call to foo(). While this behavior is by design, it is certainly confusing to the casual reader and should probably be avoided. The increment should really be done in a separate statement after the call to foo()


share|improve this answer
No, it doesn't, but you can't see that in this example because test isn't global and VS2002 evaluated the last argument first (legal and somewhat logical for a stack) –  MSalters Sep 21 '08 at 23:04
add comment

According to the C standard, it is undefined behaviour to have more than one references to a variable in a single sequence point (here you can think of that as being a statement, or parameters to a function) where one of more of those references includes a pre/post modification. So: foo(f++,f) <--undefined as to when f increments. And likewise (I see this all the time in user code): *p = p++ + p;

Typically a compiler will not change its behaviour for this type of thing (except for major revisions).

Avoid it by turning on warnings and paying attention to them.

share|improve this answer
add comment

Um, now that the OP has been edited for consistency, it is out of sync with the answers. The fundamental answer about order of evaluation is correct. However the specific possible values are different for the foo(++test, test); case.

++test will be incremented before being passed, so the first argument will always be 1. The second argument will be 0, or 1 depending on evaluation order.

share|improve this answer
add comment

It's "unspecified behavior", but in practice with the way the C call stack is specified it almost always guarantees that you will see it as 0, 0 and never 1, 0.

As someone noted, the assembler output by VC pushes the right most parameter on the stack first. This is how C function calls are implemented in assembler. This is to accommodate C's "endless parameter list" feature. By pushing parameters in a right-to-left order, the first parameter is guaranteed to be the top item on the stack.

Take printf's signature:


Those ellipses denote an unknown number of parameters. If parameters were pushed left-to-right, the format would be at the bottom of a stack of which we don't know the size.

Knowing that in C (and C++) that parameters are processed left-to-right, we can determine the simplest way of parsing and interpreting a function call. Get to the end of the parameter list, and start pushing, evaluating any complex statements as you go.

However, even this can't save you as most C compilers have an option to parse functions "Pascal style". And all this means is that the function parameters are pushed on the stack in a left-to-right fashion. If, for instance, printf was compiled with the Pascal option, then the output would most likely be 1, 0 (however, since printf uses the ellipse, I don't think it can be compiled Pascal style).

share|improve this answer
add comment

C doesn't guarantee the order of evaluation of parameters in a function call, so with this you might get the results "0 1" or "0 0". The order can change from compiler to compiler, and the same compiler could choose different orders based on optimization parameters.

It's safer to write foo(test, test + 1) and then do ++test in the next line. Anyway, the compiler should optimize it if possible.

share|improve this answer
add comment

The order of evaluation for arguments to a function is undefined. In this case it appears that it did them right-to-left.

(Modifying variables between sequence points basically allows a compiler to do anything it wants.)

share|improve this answer
add comment

The compiler might not be evaluating the arguments in the order you'd expect.

share|improve this answer
add comment
