Консультация № 72769
26.01.2007, 17:42
0.00 руб.
0 7 7
Почему данная программа выводит на екран 4 3 2, а не 2 3 4, ведь по идее здесь используется операция инкримент, которая должна сначала увеличить n на единицу, получить 2, потом еще, получить 3, потом - 4, и вывести.



Приложение:
main(){ int n=1; printf("%d %d %d",++n,++n,++n); }

Обсуждение

Неизвестный
26.01.2007, 17:51
общий
это ответ
Здравствуйте, Platon!
Насколько я знаю, компилятор не гарантирует тот порядок вычисления аргументов функции, который указан в вызове. Поэтому операции инкремента могут производиться в любом порядке, в вашем случае - сначала вычисляется 4й аргумент, потом 3й, потом 2й
Неизвестный
26.01.2007, 18:01
общий
это ответ
Здравствуйте, Platon!

в стандарте C и C++ не определен порядок обработки аргументов фунции.
судя по всему у вас параметры обрабатываются справа на лево.
у меня вот в gcc выводит
4 4 4

я бы посоветовал избегать подобных фокусов

Неизвестный
26.01.2007, 18:01
общий
это ответ
Здравствуйте, Platon!
Логичнее всего предположить, что printf подставляет аргументы с конца строки форматированния.
Неизвестный
26.01.2007, 18:08
общий
это ответ
Здравствуйте, Platon!
В стандарте порядок вычисления аргументов неопределен (5.2.2):

8 The order of evaluation of arguments is unspecified. All side effects
of argument expression evaluations take effect before the function is
entered. The order of evaluation of the postfix expression and the
argument expression list is unspecified.


Приложение:
Последний черновой вариант стандарта (а так он платный):http://ra.dkuug.dk/jtc1/sc22/open/n2356/
Неизвестный
26.01.2007, 18:55
общий
это ответ
Здравствуйте, Platon!
Насколько я помню, еще Страурступ писал, что нельзя гарантировать, в каком порядке будут вычислять аргументы, передаваемые в функцию.
В вашем случае они вычисляются справа налево.
Неизвестный
27.01.2007, 10:30
общий
это ответ
Здравствуйте, Platon!
Потому что функция считывает параметры справа налево.
Сначала увеличивается третий параметр и в третьей позиции будет выводится 2,
потом второй параметр и во второй позиции будет выводиться 3 и т.д.
Пример можно изменить так (см.приложение).
Удачи!


Приложение:
main(){ int n=5; printf("%d %d %d",--n,--n,--n); }
Неизвестный
27.01.2007, 15:34
общий
это ответ
Здравствуйте, Platon!

Никогда не используйте подобных выражений. ANSI C++ не дает никаких гарантий на то или иное поведение подобного кода. Используйте оператор инкремента/декремента не более одного раза в одном операторе. Сам господин Страуструп пишет о том, что таких случаев нужно избегать.
Другой пример: array[++i] = ++i;
Однако, отвечу на ваш вопрос конкретно.
Функция printf объявлена как __cdecl, что, кроме прочих нюансов, горовит компилятору, что параметры передаются в функцию через стек, причем добавляются в него справа налево. Предполагаемые действия компилятора: инкрементируем n, добавляем n в стек, инкрементируем n, добавляем n в стек, инкрементируем n, добавляем n в стек, добавляем в стек адрес строки формата. Функция printf анализирует строку формата и, при нахождении ссылки на подстановку целого числа, берет из стека ближайшие от адреса строки формата 4 байта. Т.о. там будет расположено число n, которое было добавлено в стек последним, имеющее значение 4. Дальше последуют 3 и 2.
Но возможно и другое поведение компилятора. Например, сначала n трижды инкрементируется, а потом трижды передается в функцию. Тогда результат, очевидно, будет 4 4 4. Мало ли других вариантов, поэтому на разных компиляторах результат может быть разным.
Возможно, поведение было бы другим, если бы функция была не __cdecl, а, например, __fastcall (передача параметров через регистры).

PS Ценю ваше стремление к познанию тонких мест в программировании.
Форма ответа