Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
alsav22
5416 / 4812 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
#1

Инкремент и вывод на консоль. Непонятное. - C++

11.08.2011, 02:05. Просмотров 632. Ответов 6
Метки нет (Все метки)

Объясните, пожалуйста, почему, если так:
C++
1
2
3
int i = 5; 
cout << i << "  "; 
cout << ++i << "\n";
, то на консоль выводится всё правильно: 5 6. А если расположить так:
C++
1
2
int i = 5; 
cout << i << "  " << ++i << "\n";
, то выводится: 6 6?
Лучшие ответы (1)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Paporotnik
383 / 227 / 7
Регистрация: 06.07.2011
Сообщений: 512
11.08.2011, 02:11     Инкремент и вывод на консоль. Непонятное. #2
ну очевидно же, что "обход" вывода идет справа налево. сначала инкрементируем, потом выводим дважды.
с инкрементом/декрементом аккуратнее надо работать. особенное если у тебя в одной строке переменная используется несколько раз.
Сыроежка
Заблокирован
11.08.2011, 02:33     Инкремент и вывод на консоль. Непонятное. #3
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от alsav22 Посмотреть сообщение
Объясните, пожалуйста, почему, если так:
C++
1
2
3
int i = 5; 
cout << i << "  "; 
cout << ++i << "\n";
, то на консоль выводится всё правильно: 5 6. А если расположить так:
C++
1
2
int i = 5; 
cout << i << "  " << ++i << "\n";
, то выводится: 6 6?
На самом деле имеет место неопределенное поведение. На одних компиляторах может выдать, как у вас, (6, 6), а на других как (5, 6 )/ Дело в том, что оператору << соответствует вызов оператор-функции operator <<( std::cout, value ); а порядок вычисления аргументов функции не определен. То есть чтобы ыбло более понятно, то ваше выражение можно переписать, как

C++
1
operato<<r( operator<<( operator<<( operator <<( std::cout, i ), " " ), ++i ), "\n" );
В самом внешнем вызове компилятор может сначала "вычислить" выражение "\n", а затем левое выражение, которое в свою очередь представляет вызов оператора-функции. А может поступить наобороь, то есть сначала вычислить левое выражение, то есть вызвать оператор-функцию, а затем "вычислить" правое выражение "\n".

То есть порядок вычисление параметров функции стандартом не установлен, а потому поведение вашего выражения неопределено. Это равносильно вызову f( i, ++i ), то есть сначала может быть вычислено значение левого выражения, а затем правого выражения. А может быть и наоборот, то есть сначала будет вычислено правое выражение, а затем левое. Просто обычно компиляторы начинают именно с правого выражения, так как так легче заносить параметры в стек вызова в соответствии с соглашениями вызова языка С.
alsav22
5416 / 4812 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
11.08.2011, 03:02  [ТС]     Инкремент и вывод на консоль. Непонятное. #4
Цитата Сообщение от Сыроежка Посмотреть сообщение
На самом деле имеет место неопределенное поведение. На одних компиляторах может выдать, как у вас, (6, 6), а на других как (5, 6 )/ Дело в том, что оператору << соответствует вызов оператор-функции operator <<( std::cout, value ); а порядок вычисления аргументов функции не определен. То есть чтобы ыбло более понятно, то ваше выражение можно переписать, как

C++
1
operato<<r( operator<<( operator<<( operator <<( std::cout, i ), " " ), ++i ), "\n" );
В самом внешнем вызове компилятор может сначала "вычислить" выражение "\n", а затем левое выражение, которое в свою очередь представляет вызов оператора-функции. А может поступить наобороь, то есть сначала вычислить левое выражение, то есть вызвать оператор-функцию, а затем "вычислить" правое выражение "\n".

То есть порядок вычисление параметров функции стандартом не установлен, а потому поведение вашего выражения неопределено. Это равносильно вызову f( i, ++i ), то есть сначала может быть вычислено значение левого выражения, а затем правого выражения. А может быть и наоборот, то есть сначала будет вычислено правое выражение, а затем левое. Просто обычно компиляторы начинают именно с правого выражения, так как так легче заносить параметры в стек вызова в соответствии с соглашениями вызова языка С.
Какое правило можно из этого вывести? Чего следует избегать?
Сыроежка
Заблокирован
11.08.2011, 03:17     Инкремент и вывод на консоль. Непонятное. #5
Следует избегать конструкций вида f( i, ++i )
Mr.X
Эксперт С++
3048 / 1693 / 265
Регистрация: 03.05.2010
Сообщений: 3,867
11.08.2011, 07:55     Инкремент и вывод на консоль. Непонятное. #6
Цитата Сообщение от alsav22 Посмотреть сообщение
Какое правило можно из этого вывести? Чего следует избегать?
Между двумя точками последовательности (sequence points) (если грубо, то в пределах одного выражения) нельзя несколько раз изменять одну и ту же переменную, либо считывать ее значение после модификации, так как это ведет к неопределенному поведению.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
11.08.2011, 12:01     Инкремент и вывод на консоль. Непонятное.
Еще ссылки по теме:
Неверный вывод в консоль C++
C++ Вывод чисел на консоль
C++ Вывод текста на консоль в C++
C++ Вывод псевдографики в консоль
C++ Вывод массива на консоль

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
alsav22
5416 / 4812 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
11.08.2011, 12:01  [ТС]     Инкремент и вывод на консоль. Непонятное. #7
Благодарю всех!
Yandex
Объявления
11.08.2011, 12:01     Инкремент и вывод на консоль. Непонятное.
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru