This has nothing to do with printf, and everything to do with the order in which the parameters are evaluated and the way the compiler executes your code. The behavior is undefined, and the results will depend on your compiler, calling convention, and phase of the moon.
In both your examples, the rules of pre/post incrementing are taking precedence. Your particular compiler understands that it must use the value of i
before evaluating the increment, and is giving precedence to the parameter that invokes a function call over the one that doesn't. Your second usage of the variable i
is causing the compiler to insert an intermediary statement in the process of calling printf
,
It's important to note that i++
doesn't mean (as is commonly taught) "increment i after executing this line", it just means "increment i at some point after giving me its value, and before executing the next line". That's a lot of wiggle room for the compiler to do what is formally called "undefined behavior."
As @Als points out in a comment, you've managed to combine both undefined and unspecified behaviors in one line of code.