Please, can anybody explain this #C #programming #riddle? It was originally intended as example for first lesson of C course for beginners, but I fell into trap!

The source:

#include <stdio.h>

void main(void)
{
int a=1, b=1;
printf("Hello++: a==%d, b==%d, a++==%d, ++b==%d, a==%d, b==%d, a--==%d, --b==%d, a==%d, b==%d\n",a,b,a++,++b,a,b,a--,--b,a,b);
}

The output, when compiled by #gcc:

Hello++: a==1, b==1, a++==0, ++b==1, a==1, b==1, a--==1, --b==1, a==1, b==1

(Hint: it works as expected, if you separate the single printf into 5 printf-s with 2 arguments each. The problem is unexpected behavior of C++-ish ++ and -- operators, when used multiple times as multiple function arguments. Remainds me of multiple evaluation of macro arguments, or something like that)

@xChaos The order of evaluation of function arguments is undefined in both C and C++

@mvidner Ok. I suspected this.

It makes some sense: a-- evaluates as 1, returns 0, a++ evaluates as 0 and returns 1. So it possibly just evaluates arguments from right to left.

BTW this is gcc beaviour, I was told, that in clang it is evaluated left to right.

Because printf() is function with variadic arguments, it may be artifact of how va_args() is currently implemented in gcc (?). The right-to-left evaluation may make some sense, because the results of evaluation are sequentially placed on the stack... but I am really not sure.

@mvidner if compiled with

-Wall

it really produces warning: operation on ‘a’ may be undefined [-Wsequence-point]

@xChaos all those UB (undefined behavior) traps are there to make the lives of COMPILER IMPLEMENTERS easier. Life priorities from 1970s *rolls eyes*

@mvidner I really expected evaluation order from left to right, like with expressions. And it probably used to be like this in the past, because clang does it.

But still it is weird, because --b==1 would suggest evaluation from left to right!

UndefinedBehaviorSanitizer — Clang 23.0.0git documentation

@xChaos my rule is simple: if you do ++ or -- on a variable, only evaluate that varible once in enture statement. Apply this to all languages, including those with well defined behavior.
This is not a riddle, it's a code that should not be written. Were it up to me, this code wouldn't compile.
@xChaos order of argument evaluation is unspecified.
@pinskia yes, it is not even reverse order. a seems to be evaluated from right to left, but b the other way around...
@xChaos But with the odering being unspecified, modifying the same variable without a sequence point is undefined. And arguments comma are not sequence points.

@pinskia yes, I learnt already, then if compiled with -Wall, there are even warnings about that.

Still, it is very counter-intuitive behavior.

@xChaos I don't disagree. Maybe it will fixed in C3x :).