0

I want to do something like this printf("%d,%d",array[c], array[c+1]), with only one variable that increases in every iteration. I wrote the following code, and I expected "1,2" to stdout, I was wrong:

#include <stdio.h>
int main()
{
    int c = 1;
    printf("%d,%d",c++,c++); /* 2,1 */
    //printf("%d,%d",c,c++);   /* 2,1 */
    //printf("%d,%d",c++,c);   /* 1,2 */
}

If I try doing printf("%d,%d",c++,c) and printf("%d,%d",c,c++), I can see that there is no defined order of execution of the "c++" statements.

Could somebody explain how the code I wrote compiles to ? And why and how does it change according to the position of the "c++" statements.

  • 2
    The order is unspecified. But this is also an undefined behavior to `c++` twice without sequence point in between. – Eugene Sh. Feb 06 '19 at 19:08

3 Answers3

5

The order of evaluation of the arguments in a function call is unspecified, and there is no sequence point between the evaluation of these expressions. This means that - if one expression alters as a side effect an object (like the value of c) which is also accessed by another expression - it is unpredictable what the outcome of these expressions will be. For that reason, the language defines such cases as undefined behaviour (cf., for example, this online C standard draft):

6.5 Expressions

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

Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
3

The order of evaluation of function arguments is unspecified. As ++ operator has side effects - it is undefined behavior to make two side effects inside one expression (function call).

1

The order in which arguments to a function are evaluated is not defined by the C standard. The order in which arguments are passed to a function are normally defined by the calling convention, though that still leaves the order of evaluation up to the compiler.

For example, if you have a calling convention where parameters are pushed on the stack right to left (this is ubiquitous on x86-32), the assembly generated for printf("%d %d", c, c++); might look like:

push eax ; arg 3
push edx ; arg 2
push offset format_string
call _printf
add esp, 12

However, we still can't reason about which order eax and edx were populated with the value of c and c++.

Govind Parmar
  • 20,656
  • 7
  • 53
  • 85