int f() {
    static int i=0;
    return ++i;
}
int g() {
    return f() + f();
}
Возвращает ли g() 3 или является результатом undefined?
int f() {
    static int i=0;
    return ++i;
}
int g() {
    return f() + f();
}
Возвращает ли g() 3 или является результатом undefined?
6.5.2.2 Функциональные вызовы
...
10 есть точка последовательности после оценок указателя функции и фактического аргументов, но до фактического вызова. Каждая оценка в вызывающей функции (включая другие вызовы функций), которые иначе не секвентируются до или после выполнение тела вызываемой функции неопределенно упорядочено по отношению к выполнение вызываемой функции. 94)
94) Другими словами, выполнение функций не "чередуется друг с другом"
Результат состоит в том, что между каждым ++i существует точка последовательности, поскольку она является частью вызова функции. Таким образом, это поведение четко определено.
Действительно ли это делает то, что вы намереваетесь, другое дело. Обратите внимание, что в какой-то момент вы рискуете подписью переполнения, которая undefined. И, как указывали другие, f() - f() может не дать результата, которого вы ожидаете (оценка в правильном направлении в этом случае не гарантируется).
Оценки двух операндов оператора + не подвержены последовательности 1.
Существует точка последовательности непосредственно перед вызовом фактической функции 2. Эта точка последовательности достаточно, чтобы отделить модификации статической переменной i, делая все выражение неопределенно секвенированным, а порядок функции вызывает неуказанный 3.
Таким образом, поведение остается определенным, и первый вызов функции g всегда будет давать 3, так как неуказанный порядок вызова функции не влияет на результат.
Определяется программа, содержащая неопределенное поведение 4.
(Все цитаты взяты из: ISO/IEC 9899: 201x)
  1 (6.5 Выражения 3) 
Кроме указанных
позже, побочные эффекты и вычисления значений подвыражений не имеют никакого значения.
  2 (6.5.2.2 Функциональные вызовы 10) 
После оценок указателя функции и фактической точки есть точка последовательности
аргументов, но до фактического вызова.
  3 (5.1.2.3 Исполнение программы 3) 
Оценки A и B неопределенно секвенированы, когда A секвенирован
либо до, либо после B, но не указано, что.
  4 (4. Соответствие 3) 
Программа, которая правильна во всех других аспектах, работающая на правильных данных, содержащая
неуказанное поведение должно быть правильной программой и действовать в соответствии с 5.1.2.3.
Нет причин для этого undefined, потому что операция + является коммутативной и потому, что для двух операций ++ есть последовательности точек последовательности.
Стандарт C точки последовательности после полного выражения, а также перед тем, как функция будет введена в вызов функции. Поэтому результаты ++ будут полностью секвенированы. Более того, поскольку + является коммутативным, порядок вызовов f() не изменяет результат.
Обратите внимание, что та же логика не относится к
return f() - f();
 потому что - не является коммутативным. Результат выражения выше не указан, т.е. Компилятор, совместимый со стандартами, может разумно создавать 1 или -1, в зависимости от порядка, в котором компилятор вызывает две функции f().
Нет причин для поведения undefined. Статическая переменная будет сохранена в пространстве памяти .BSS, и никакие ее копии не будут сделаны - компилятор справится с этим. Функция f() будет вызываться дважды, последовательно. Следующий пример аналогичен:
for (int i = 0; i < 2; ++i)
     g += f();
Если функция f() была бы вызвана двумя потоками, это привело бы к поведению undefined.
Вот цитата из C11 Раздел 6.5 Параграф 2:
Если побочный эффект скалярного объекта не зависит от другого побочного эффекта для одного и того же скалярного объекта или вычисления значения с использованием значения одного и того же скалярного объекта, поведение undefined. Если существует несколько допустимых порядков подвыражений выражения, то поведение undefined, если такой необъективный побочный эффект возникает в любом из порядков .84
Но в соответствии с разделом 5.1.2.3, параграф 3, упорядочение неопределенно упорядочено, а не не имеет последствий, поэтому первое предложение выше не применяется. Второе предложение применяется только в том случае, если в любом из упорядочений есть побочные эффекты. Но в каждом из упорядочений нет никаких побочных эффектов.
В стандарте C11 не говорится о влиянии неопределенно упорядоченных вычислений. Возможно, мы должны сделать вывод о том, что приемлемым для соответствующего компилятора является получение выходов любой из возможных последовательностей. В этой интерпретации имеется две возможные последовательности, каждая из которых приводит к g(), возвращающему значение 3.
Поэтому я считаю, что это приемлемо.
Обратите внимание, что в C99 нет раздела, соответствующего разделу 5.1.2.3 в C11. Раздел 5.5 В пункте 3 говорится, что упорядочение подвыражений и порядок, в котором происходят побочные эффекты, являются неуточненными.
"Unspecified" - это не то же самое, что "undefined".
Это заставляет меня думать, что в C99 это не поведение undefined.