Подтвердить что ты не робот

Вызывает функцию с локальными побочными эффектами дважды в том же самом выражении undefined?

int f() {
    static int i=0;
    return ++i;
}
int g() {
    return f() + f();
}

Возвращает ли g() 3 или является результатом undefined?

4b9b3361

Ответ 1

Глава и стих:

6.5.2.2 Функциональные вызовы
...
10     есть точка последовательности после оценок указателя функции и фактического аргументов, но до фактического вызова. Каждая оценка в вызывающей функции (включая другие вызовы функций), которые иначе не секвентируются до или после выполнение тела вызываемой функции неопределенно упорядочено по отношению к выполнение вызываемой функции. 94)
94) Другими словами, выполнение функций не "чередуется друг с другом"

Результат состоит в том, что между каждым ++i существует точка последовательности, поскольку она является частью вызова функции. Таким образом, это поведение четко определено.

Действительно ли это делает то, что вы намереваетесь, другое дело. Обратите внимание, что в какой-то момент вы рискуете подписью переполнения, которая undefined. И, как указывали другие, f() - f() может не дать результата, которого вы ожидаете (оценка в правильном направлении в этом случае не гарантируется).

Ответ 2

Оценки двух операндов оператора + не подвержены последовательности 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.

Ответ 3

Нет причин для этого undefined, потому что операция + является коммутативной и потому, что для двух операций ++ есть последовательности точек последовательности.

Стандарт C точки последовательности после полного выражения, а также перед тем, как функция будет введена в вызов функции. Поэтому результаты ++ будут полностью секвенированы. Более того, поскольку + является коммутативным, порядок вызовов f() не изменяет результат.

Обратите внимание, что та же логика не относится к

return f() - f();

потому что - не является коммутативным. Результат выражения выше не указан, т.е. Компилятор, совместимый со стандартами, может разумно создавать 1 или -1, в зависимости от порядка, в котором компилятор вызывает две функции f().

Ответ 4

Нет причин для поведения undefined. Статическая переменная будет сохранена в пространстве памяти .BSS, и никакие ее копии не будут сделаны - компилятор справится с этим. Функция f() будет вызываться дважды, последовательно. Следующий пример аналогичен:

for (int i = 0; i < 2; ++i)
     g += f();

Если функция f() была бы вызвана двумя потоками, это привело бы к поведению undefined.

Ответ 5

Вот цитата из 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.