Последовательность вызовов функций (C++)

result= function_1()*function_2();

Я пишу код, как указано выше. Что я хочу знать, так это то, что при выполнении умножения какая функция вызывается первой? Это связано с тем, что первая вызванная функция может влиять на результат, возвращаемый другой функцией. Я предположил, что сначала вызывается function_1(), и когда я попробовал, то увидел, что это действительно так. Однако всегда ли так? Зависит ли это от того, какой компилятор я использую или от системы, в которой работаю?


person oicrisah    schedule 29.10.2014    source источник


Ответы (2)


Порядок оценки не указан стандартом C++ (или C) (см. ответ Влада). Если ваши function_1 или function_2 имеют значительные побочные эффекты, они могут стать < href="http://en.wikipedia.org/wiki/Unspecified_behavior" rel="nofollow noreferrer">неопределенное поведение, которого вам следует избегать (например, вам следует избегать неопределенное поведение). А в некоторых случаях (встроенные функции с сильной оптимизацией) вычисления могут быть перемешаны.

Подумайте о таких странных случаях, как

 static int i;
 int function_1(void) { i++; return i; }
 int function_2(void) { i+=2; return 3*i+1; }

Вероятно, это зависит от реализации и может зависеть от фактического компилятора и флагов оптимизации.

Вы должны кодировать так, как если бы порядок вызовов функций был полностью случайным и невоспроизводимым (даже если на практике он может быть воспроизводимым). Точно так же вы не должны ожидать какого-то определенного порядка оценки аргументов (например, в f(i++, ++j) вы не знаете, был ли сначала увеличен i или j), даже если для данного компилятора этот порядок может быть фиксированным. Опять же, вы должны представить себе совершенно случайный и невоспроизводимый порядок.

Как прокомментировал Дэвид Шварц, если вам небезразличен порядок, вы должны явно кодировать некоторые точки последовательности

Наконец, если ваш код зависит от какого-то порядка, он совершенно нечитаем, и по этой простой причине удобочитаемости вам следует избегать такого кодирования.

person Basile Starynkevitch    schedule 29.10.2014
comment
Если вам не все равно, вам нужно вставить точку последовательности между вызовами функций. Как result=function_1(); result*=function_2();. - person David Schwartz; 29.10.2014
comment
Это не может привести к неопределенному поведению (если только function_1 или function_2 не являются макросами). До и после тела функции есть точка следования. - person M.M; 29.10.2014
comment
Если function_1 и function_2 встроены, я полагаю, что компилятор может оптимизировать для смешивания обоих кодов... - person Basile Starynkevitch; 29.10.2014
comment
Это все еще не может вызвать UB, компилятор должен подчиняться правилу «как если бы» - person M.M; 29.10.2014
comment
Спасибо за УБ. Улучшил мой ответ! - person Basile Starynkevitch; 29.10.2014
comment
Это не указано слишком расплывчато. Похоже, стандарт C++ ничего не говорит об этом. Но это так. Он указывает, что порядок оценки не указан. Таким образом, более точным утверждением было бы то, что порядок вычисления подвыражений не указан. - person Kerrek SB; 29.10.2014
comment
Я думаю, что умножение дает одинаковый результат в любом случае (сначала оценивается слева или сначала оценивается право). Эту проблему можно проверить, поставив точки останова в каждой функции и проверив, какой последовательности будет следовать используемый компилятор. - person Ali Kazmi; 29.10.2014
comment
Не с static int i; int function_1(void) {i+=1; return i;}; int function_2(void) {i+=2; return i;} - person Basile Starynkevitch; 29.10.2014

Согласно стандарту C++ (1.9 Выполнение программы)

15 Если не указано иное, вычисления операндов отдельных операторов и подвыражений отдельных выражений не упорядочены.

Итак, в этом выражении

result= function_1()*function_2();

некоторые компиляторы могут вычислять сначала функцию_1(), а затем функцию_2(), в то время как другие компиляторы могут сначала оценивать функцию_2() и только потом функцию_1(). Даже если вы пишете как

result= (function_1())*(function_2());

or

result= (function_1())*function_2();

or

result= function_1()*(function_2());

ничего не изменится относительно порядка вычисления операндов.

person Vlad from Moscow    schedule 29.10.2014