В языке C порядок вычисления аргументов функции не определён стандартом (до C99 включительно). Аргументы могут вычисляться слева направо, справа налево или в любом другом порядке (на усмотрение компилятора или архитектуры).
void fn(int a, int b) { /* ... */ } int x = 1; fn(x++, x++); // порядок вычисления x++ и x++ не определён!
"В какой последовательности вычисляются аргументы функции в C и можно ли на это полагаться при написании кода?"
Частая ошибка — считать, что аргументы вычисляются слева направо (по аналогии с выражениями). На практике каждый вызов функции компилируется на усмотрение компилятора (и платформы).
void foo(int a, int b, int c); int x = 1; foo(x++, x++, x++); // результат зависит от порядка вычисления аргументов
Настоящий ответ: полагаться нельзя — поведение не определено!
История
В многоплатформенном продукте программист писал
push(stack, stack->size++, data);. На большинстве платформ всё работало, но на одной размер стека увеличивался до передачи данных, на другой — после. Данные "терялись" или адресовались некорректно, ошибка проявлялась редко и была очень сложна для отладки.
История
В библиотеке сетевого протокола функция логирования вызывалась с выражениями-аргументами, инкрементирующими статистические счетчики. Отчёты статистики генерировались неверно: у разных клиентов индексы счетчиков отличались, потому что выполнялись не в ожидаемом порядке.
История
В интерфейсе управления оборудованием функция инициализации передавала указатели и смещения с инкрементом внутри аргументов (типа
init(ptr++, cnt++);). На одних процессорах железо инициализировалось правильно, а на других возникал сбой, причину долго искали в аппаратуре, хотя проблема была в некорректном коде C.