In what order does C evaluate function arguments? The honest answer: whatever order the compiler likes — the standard leaves argument evaluation order unspecified. That alone is survivable. But combine it with a side effect, as in printf("%d %d", x, x++), and you cross into undefined behavior. We ran this exact code — from two questions in our C Programming Quiz App — on gcc and clang, and got different output from each compiler. Here’s the proof, and the rules behind it.
The Quiz Questions
Question 1:
int x = 5;
printf("%d %d", x, x++);
- 5 5
- 6 5
- 5 6
- Undefined behavior
Question 2 — same trap, pre-increment flavor:
int a = 5;
printf("%d %d", a, ++a);
- 5 6
- 6 6
- 5 5
- Undefined behavior
The Correct Answer to Both: Undefined Behavior
Two rules combine here:
- Argument evaluation order is unspecified. C never promises left-to-right. A compiler may evaluate
x++beforex, or after, or interleave them. - The side effect is unsequenced. One argument modifies
xwhile another reads it, with no sequence point between them. Per C11 §6.5p2, an unsequenced side effect plus a use of the same object is undefined behavior — not merely “one of two possible outputs”.
Don’t take the standard’s word for it — take the compilers’. Same source file, real runs:
$ gcc -Wall quiz1.c # gcc 13.3, Ubuntu 24.04 quiz1.c:5:27: warning: operation on 'x' may be undefined [-Wsequence-point] $ ./quiz1 6 5 $ clang -Wall quiz1.c # Apple clang 21, macOS quiz1.c:5:27: warning: unsequenced modification and access to 'x' [-Wunsequenced] $ ./quiz1 5 5
gcc printed 6 5; clang printed 5 5. The pre-increment version splits the same way: gcc prints 6 6, clang prints 5 6. One program, two mainstream compilers, two different answers — the definition of code you can’t ship.
Why Each Wrong Answer Is Wrong
Why not “5 5”?
This assumes left-to-right evaluation: read x (5), then x++ yields 5. That’s exactly what clang did — and exactly what gcc didn’t. An answer that depends on which compiler you happen to use isn’t an answer.
Why not “6 5”?
This assumes right-to-left: x++ first (yields 5, x becomes 6), then read x (6). gcc’s observed behavior — historically common because arguments were pushed onto the stack right-to-left. Still just an implementation accident, contradicted by clang on the very same code.
Why not “5 6”?
For the first question this trace requires reading x before the increment but printing the incremented value second — plausible only by misreading what x++ yields (it yields the old value). For the pre-increment version, “5 6” is clang’s real output (++a yields the new value, 6) — but again, gcc disagrees, printing “6 6”. Whenever two conforming compilers disagree, the question has no defined answer.
Unspecified vs. Undefined — the Distinction That Matters
This question is a two-layer trap, and the layers are worth separating:
- Unspecified behavior: the standard offers a set of valid options and doesn’t say which one you get. Argument evaluation order by itself is unspecified —
printf("%d %d", f(), g())may callforgfirst, but each call happens exactly once and the program is still correct. - Undefined behavior: all bets off. The moment one argument modifies an object another argument reads —
xandx++— you’re not choosing between “5 5” and “6 5” anymore. The standard permits anything, including outputs matching neither trace.
The fix is the same as for every sequencing bug — do the modification in its own statement:
int old = x;
x++;
printf("%d %d", x, old); /* well-defined on every compiler: 6 5 */
How to Catch This Bug
gcc -Wall file.c # warning: operation on 'x' may be undefined [-Wsequence-point] clang -Wall file.c # warning: unsequenced modification and access to 'x' [-Wunsequenced]
Both compilers flag it at compile time with standard warnings. If your build treats warnings as errors (-Werror), this bug can’t even compile — the cheapest possible fix.
Frequently Asked Questions
Does C evaluate function arguments left to right?
No — the order is unspecified. clang typically evaluates left-to-right, gcc typically right-to-left, and both are conforming. Never write code whose meaning depends on argument evaluation order.
Is printf(“%d %d”, x, x++) just compiler-dependent?
It’s worse than that: it’s undefined behavior, because x++ modifies x while another argument reads it, unsequenced. “Compiler-dependent” would mean each compiler gives you one of the valid answers. Undefined means there is no valid answer.
Is f(g(), h()) also a problem?
Not by itself. The order of calling g and h is unspecified, but function calls don’t overlap, so unless g and h touch the same data, the program is fine. The undefined-behavior line is crossed when arguments have unsequenced side effects on the same object.
Related Reading
- Increment and Decrement Operators in C
- Arithmetic Operators in C
- C Aptitude Questions and Answers
- Pointers in C – Complete Guide
Recommended Books
- The C Programming Language – Kernighan & Ritchie (India) | Amazon.com
- C Programming: A Modern Approach – K.N. King (India) | Amazon.com
These are questions #113 and #145 in the C Programming Quiz App — 155 questions with explanations covering operators, pointers, memory, and more.
Download on Google Play →