Большой Воронежский Форум
» Программирование>c++ cout
LSL 18:29 06.11.2003
Друг-сишник задался вопросом:

i = 1

cout << i << i++ << i

Почему на выходе 2 1 2, ведь должно 1 1 2 ? [Ответ]
Noname 18:42 06.11.2003
потому что так писать нельзя. Поведение кода здесь будет совершенно неопределенным. Компилятор совсем не обязан вычислять эти выражения в порядке вывода, он это может сделать как угодно. Единственное, что можно сказать, что в середине будет единица.
А потом теоретически возможны варианты:

1 1 1
1 1 2
2 1 1
2 1 2

Просто не надо писать такой код. [Ответ]
RomanPshenichny 18:58 06.11.2003
VC 7.1 release выдает 112, а debug 212.

Неопределен порядок вычисления выражений между точками следования (sequency point). Результат может быть любым.

Этот код аналогичен:

func ( func ( func (0, i), i++ ), i); [Ответ]
Noname 19:05 06.11.2003
RomanPshenichny совершенно верно... [Ответ]
Павел-Kikoz 14:45 07.11.2003
Я, конечно, не уверен.. Но разве операторы не выполняются слева - направо? Тогда результат 112 логичен.. [Ответ]
Unforgiven 09:02 10.11.2003
И даже более того:
$ g++ z.cpp -o z && ./z
211

$ g++ z.cpp -O2 -o z && ./z
112

Как видно, если добавить оптимизацию (-O2), то результат другой.

$gcc -v | grep version
gcc version 3.2.1 (ALT Linux, build 3.2.1-alt2) [Ответ]
Павел-Kikoz 09:32 10.11.2003
Вот, блин.. И отлаживай потом такое..
В предыдущем посте имел в виду справа налево... Да, похоже, они выполняются как им приспичит
[Ответ]
Unforgiven 10:03 10.11.2003
Павел-Kikoz Чтобы не отлаживать такое, не надо такое писать. Кстати, если

cout << i << i++ << i

заменить на

printf("%d%d%d", i, i++, i)

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

2 1 1 [Ответ]
RomanPshenichny 11:55 10.11.2003
Павел-Kikoz

> Да, похоже, они выполняются как им приспичит

Может стоит выучить язык на котором пишите? [Ответ]
zic 19:31 10.11.2003
Веревка достаточной длины чтобы выстрелить себе в ногу . Или как правильно писать программы на Си . [Ответ]
LSL 21:36 10.11.2003
Спасибо. Друг будет доволен бедный друг...он обречён : ): ) [Ответ]
Павел-Kikoz 09:27 11.11.2003
Unforgiven
Ды я и не пишу таких конструкций, себе дороже...
Кстати, RomanPshenichny утверждает, что "этот код аналогичен
func ( func ( func (0, i), i++ ), i);"
RomanPshenichny
Язык-то стоит выучить... Только я не уверен, что его легко выучить на 100% (сколько там странц стандарт занимает?) А в неком достаточном объеме я его знаю (смею надеяться) [Ответ]
zic 09:31 11.11.2003
Павел-Kikoz
Какой стандарт ?
с каких это пор реализации языков от MS соответсвуют каким то стандартам ? И уж точно не ансишным .
Может спецификация ?
[Ответ]
NonSoluS 11:59 11.11.2003

Сообщение от :
cout << i << i++ << i

заменить на

printf("%d%d%d", i, i++, i)

тогда и <stdio.h> подрубай.... [Ответ]
Unforgiven 13:28 11.11.2003
DoZeR, само собой.
Только к чему ты это сказал? Тут где-нибудь приведен полный текст программы? [Ответ]
Павел-Kikoz 15:52 11.11.2003
zic
Стандарт и спецификация использовались мной как синонимы. Ок, спецификация языка с++.
cout и оператор ++ это явно стандатрные переносимы вещи, не всякие там __property
Да и тут не только MS VC касается, как я понял...
Ну ладно, чот-то народ начал придираться к словам...
Ну не работает и не работает, черт с ним.
[Ответ]
zic 16:23 11.11.2003
Ессно не только MS .
НУ так речь то не о том ? [Ответ]
RomanPshenichny 21:20 11.11.2003
Павел-Kikoz

> Кстати, RomanPshenichny утверждает, что "этот код
> аналогичен func ( func ( func (0, i), i++ ), i);"

cout << i << i++ << i, это:

( ( (cout::operator << (i) )::operator << (i++) )::operator << (i)

и для педантов:

( ( (std::basic_ostream<char,std::char_traits<char> >::operator<< (i) )::operator << (i++) )::operator << (i).

В функциональном виде код аналогичен func ( func ( func (0, i), i++ ), i). В котором тоже будет наблюдатся такое же неопределенное поведение.

Точка следования в обоих вариантах одна. Все пераметры operator << и func вычисляются до вызова самих функций. Т.е. сначала посчитали i, i++, i, а потом уже вызвали функции. Порядок вычисления i, i++, i внутри одной точки следования не определен. Что такое точка следования -- читайте в книжках по C++.

> сколько там странц стандарт занимает

~700. Но это смотря каким шрифтом ;)

zic

> с каких это пор реализации языков от MS соответсвуют
> каким то стандартам ?

С 2003 года, с VC 7.1.
Казалось бы, причем тут MS? ;)
Это стандартный undefined behaviour описанный в стандарте. [Ответ]
zic 00:35 12.11.2003
RomanPshenichny
ДА я не спорю что темотаг наблюдается в любом случае .
Я просто к тому что в MS любит придумывать свои стандарты .
А не следывать общепринятым .
[Ответ]
Unforgiven 08:34 12.11.2003
RomanPshenichny, маленькое уточнение:
( ( (cout.operator << (i) ).operator << (i++) ).operator << (i) [Ответ]
Павел-Kikoz 09:38 12.11.2003
RomanPshenichny
Блин, если бы я не знал, что операторы работают как функции, я бы вообще не полез в тему
"Порядок вычисления i, i++, i внутри одной точки следования не определен." - вот именно поэтому я и написал, что все достачно сложно.
[Ответ]
Fisher 16:12 21.11.2003

Сообщение от :
Первоначальное сообщение от LSL
Друг-сишник задался вопросом:

i = 1

cout << i << i++ << i

Почему на выходе 2 1 2, ведь должно 1 1 2 ?

Ничего не должно быть, т.к. тут undefined behaviour и поэтому может быть все, что угодно, вплоть до форматирования диска.

Fisher добавил [date]1069425240[/date]:

Сообщение от :
Первоначальное сообщение от RomanPshenichny
Точка следования в обоих вариантах одна.[/B]

Все пераметры operator << и func вычисляются до вызова самих функций.

Все аргументы не обязаны вычисляться до вызова первой из функций.

Сообщение от :
Т.е. сначала посчитали i, i++, i, а потом уже вызвали функции. Порядок вычисления i, i++, i внутри одной точки следования не определен.

Дело не в том, что не определен порядок вычисления подвыражений внутри выражений, а в том, что нет гарантированных точек следования между вычислением i и i++. Undefined behaviour. [Ответ]
Вверх