Skip to content

70 Advanced The Hundred

Argument Roulette

your arguments, the compiler's order

#include <iostream>

void log_pair(int a, int b) { std::cout << a << ", " << b << "\n"; }

int main() {
    int i = 0;
    log_pair(i++, i++);
}

Run it. What does it print?

Answer

GCC 11 on x86-64 prints 1, 0. The very same source under Clang 18 prints 0, 1. Both compilers are right.

Why

C++ deliberately leaves the evaluation order of function arguments unspecified — still true in C++20. GCC evaluates these arguments right-to-left, so the second i++ runs first (yielding 0) and the first then yields 1; Clang goes left-to-right and prints 0, 1. Since C++17 the two arguments are at least indeterminately sequenced — one finishes before the other starts — so the result is merely unpredictable; before C++17 they were unsequenced, making this undefined behavior, not just roulette. C++17 did nail down the neighbors: a << b << c now evaluates left-to-right, and in x.f(args) the object x is evaluated before any argument. Both compilers smell the trap: GCC warns under -Wall (operation on 'i' may be undefined [-Wsequence-point]), Clang even at default settings (multiple unsequenced modifications to 'i' [-Wunsequenced]).

The fix

Sequence it yourself — separate statements have a guaranteed order:

int first = i++;
int second = i++;
log_pair(first, second);   // 0, 1 — on every compiler

Takeaway: never let two argument expressions touch the same state — if the order matters, evaluate into named locals first.

Try it: g++ -std=c++17 main.cpp -o demo && ./demo

Open in Compiler Explorer ↗ Quiz this entry