Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Угадайте, что получиться...


Автор: val 9.3.2005, 17:01
Угадайте с двух раз, какое значение получит переменная с, 47 или 117, после такого вычисления
Код

a=5; 
b=10;
с = a*b - 36 / (a=(b+2));


Сначала подумайте! Будьте честными перед собой и товарищами!

Потом я расскажу про проблемы портирования, связанные с этим выражением...

Автор: maxim1000 9.3.2005, 17:15
47
Добавлено @ 17:15
это я так...просто... smile
а вообще, если по-умному, надо бы в стандарт заглянуть...

Автор: val 9.3.2005, 17:21
Ну, какие еще варианты?

Автор: Enflout 9.3.2005, 17:23
117
Вычисляем то справа налево вроде. smile

Автор: maxim1000 9.3.2005, 17:25
Цитата(val @ 9.3.2005, 15:01)
какое значение получит переменная с, 47 или 117

Цитата(maxim1000 @ 9.3.2005, 15:15)
47

Цитата(val @ 9.3.2005, 15:21)
Ну, какие еще варианты?

и действительно, какие же еще могут быть варианты smile

Автор: setq 9.3.2005, 17:28
это не определяется стандартом языка. вот моё ИМХО. (читай: зависит от компилятора)

Автор: val 9.3.2005, 17:31
Цитата
это не определяется стандартом языка. вот моё ИМХО. (читай: зависит от компилятора)


Цитата
Вычисляем то справа налево вроде


Вообще порядок вычислении определяется приоритетом операций...
Даю подсказку: скобки имеют самый высокий приоритет...

Автор: chipset 9.3.2005, 17:36
117 помойму.

Автор: val 9.3.2005, 17:44
да, на самом деле, правильный ответ именно 117, только вот почему такие компиляторы как VC++, Borland C++, gcc дают 47 не понятно...

Любопытно, что при включенной оптимазации на VC++ получаем тоже 117...

Добавлено @ 17:45
И как тут возможно корректное портирование?!

Автор: chipset 9.3.2005, 17:54
Я думаю что таких ситуаций вообще следует избегать, также как и:
i+++i;
Undefined behavior короче (умничаю).

Автор: maxim1000 9.3.2005, 17:57
я, к сожалению, не знаю, как реализовано вычисление подобных выражений в компиляторе, но знаю, как его в принципе можно организовать:
1. для интерпретаторов: делаем стек значений и стек операций
идем слева направо
если встречаем значение (или переменную, которую мы заменяем на ее значение) отсылаем ее в стек значений, если операцию - в стек операций
если мы видим, что операция с более низким приоритетом идет после операции с более высоким приоритетом, выполняем ту, которая с более высоким (при этом значения достаются из стека, участвуют в выполнении операции, а результат отправляется назад в стек)
со скобками посложнее: у открывающей скобки самый высокий приоритет, у закрывающей - самы низкий smile
это дает такую последовательность: когда доходим до начала выражения в скобках, его значение не будет использовано, пока не будет вычислено до конца
когда доходим до конца выражения в скобках, все операции внутри него будут выполнены
когда встречаются просто открывающая и закрывающая скобки, они просто схлопываются и остается нужное число
фукции реализуются похожим образом, только перед схлопыванием выполняется некоторый код
во-о-от...
2. для компиляторов: отличие состоит в том, чтобы как можно больше дел сделать на этапе компиляции и оставить на исполнение минимум операций
отсюда получаем:
все, что можно посчитать уже сейчас (константы всякие) - посчитать
стек операций - убрать, заменив его на простую последовательность операций (которая уже известна)
получаем просто код, представляющий из себя три типа операций:
1. записать значение в стек
2. прочитать значение из стека
3. выполнить операцию (арифметическую или функцию)

а теперь - как я размышлял, когда отвечал на вопрос:
последовательность вычислений такая:
1. a -> стек
2. видим умножение, но не выполняем, т.к. не знаем, что там дальше
3. b -> стек
4. видим "-", значит, умножение надо выполнять
5. a,b <- стек
6. a*b -> стек
7. 36 -> стек
8. видим деление и понимаем:
8.1. вычитание выполнять не стоит, т.к. сначала надо будет выполнить деление
8.2. деление тоже выполнять рановато (т.к. неизвестно, что дальше)
9. видим скобки - радуемся, что не выполнили деление smile
10. видим функцию operator=( (&a) , (b+2) ) (а вы что думали smile)
--. операция &a - на самом деле такое же значение, как и любое другое
11. &a ->стек
12. видим открывающую скобку
13. b -> стек
14. видим +
15. 2 -> стек
16. видим закрывающую скобку - выполняем плюс
17. b,2 <- стек, b+2 -> стек
18. видим еще одну закрывающую скобку - надо выполнить функцию
19. (&a), (b+2) <- стек
20. выполняем функцию operator=
21. результат -> стек
22. у нас осталось деление - выполняем
23. осталось вычитание - выполняем
Добавлено @ 17:57
ого... тут уже написали кучу всего
Добавлено @ 18:00
Цитата
да, на самом деле, правильный ответ именно 117

источник, если можно...
стандарт?
если нет, то это все - такие же домыслы, как и то, что я написал smile
Цитата
только вот почему такие компиляторы как VC++, Borland C++, gcc дают 47 не понятно...

вот мое сообщение - версия ответа на этот вопрос
Цитата
И как тут возможно корректное портирование?!

если портирование соответствует стандарту - оно корректное smile
если нет - то нет
другой вопрос: нужно ли корректное портирование или портирование с учетом компилятора исходного кода
Добавлено @ 18:01
УЖАС...посмотрел, сколько, оказывается, я написал...УЖАС...

Автор: setq 9.3.2005, 18:19
приоритет операций вещь хорошая, но что выполнится первым: f() или g() ?
Код
f() + g()
с точки зрения таблицы приоритетов операций это никак не определяется. а нет в стандарте - зелёный свет разработчикам компиляторов: делай как хочешь.

впрочем про && и || известно, что они вычисляют свой левый аргумент раньше правого. боюсь, это всё на что можно рассчитывать.

если чего-то не понял - объясните.

Автор: versus 9.3.2005, 18:21
chipset, согласен, undefined behavior. Стандарт не фиксирует в каком порядке будут вычисляться операнды оператора '-' (равно как и +, *, и / и другие, последовательность вычислений фиксируется только для '&&', '||', ',' и '?:'). Скобки здесь никак не влиють на последовательность в котором будут вычислены эти выражения.

Автор: Goryachev 9.3.2005, 20:28
Я не понимаю, почему в VC++ и в BC++ дает 47, но по стандартному приоритету операторов, должно быть 117.

Автор: bel_nikita 9.3.2005, 20:56
упс-сс smile

Автор: Дрон 9.3.2005, 21:35
Цитата(Goryachev @ 9.3.2005, 20:28)
но по стандартному приоритету операторов, должно быть 117

А в чём заключается стандартный приоритет операторов?
Обычно всё вычисляется слева направо, кроме присваивания и ещё какого-то действия (сейчас в хелпы гляну)
Добавлено @ 21:39
Вот:
Таблица приоритетов из борландовского хелпа.
Код
()    []    ->    ::    .                            left to right
! ~ + -    ++ -- & * sizeof new delete                right to left
.*    ->*                                        left to right
*    /    %                                    left to right
+    -                                          left to right
<<    >>                                           left to right
<    <=    >    >=                                left to right
==    !=                                        left to right
&                                               left to right
^                                               left to right
|                                                left to right
&&                                              left to right
||                                                right to left
?:                                                left to right
= *= /=    %= +=    -= &=    ^= |=  <<= >>=         right to left
,                                                left to right
(причём во второй строчке операции "+" и "-" -- унарные.
Добавлено @ 21:41
Так что я бы сказал, что 47.
Добавлено @ 21:44
Насчёт стандартов smile
Цитата
Order of operations is not defined by the language. The compiler is free to evaluate such expressions in any order, if the compiler can guarantee a consistent result

Автор: Fixin 9.3.2005, 22:07
Цитата
вот почему такие компиляторы как VC++, Borland C++, gcc дают 47 не понятно...

Умножение, потом вычитание деления, так что вполне логично smile . Хотя, если представить себя парсером, то получается 117 smile .
Итак, опять пришел к вопросу "что же правильно?" smile

Автор: versus 10.3.2005, 02:14
видимо правильно будет не писать такой код вовсе :-)

Автор: maxim1000 10.3.2005, 11:12
Цитата
если представить себя парсером, то получается 117

хм...а почему это знаменатель должен вычисляться раньше?
все просто - есть последняя операция - вычитание
для ее выполнения нужно посчитать левый аргемент и правый
и никакие приоритеты и скобки (по крайней мере, с точки зрения математики) не могут указать порядка их вычисления
Добавлено @ 11:12
хоть параллельно

Автор: Fantasist 11.3.2005, 03:59
Как и сказал chipset, правильно здесь - undefined behavior. И это по стандарту.
То есть компилятор волен выбирать сам, что ему вначале вычислять a*b или (a=b+2). Приоритет играет роль только тогда, когда операции зависимы друг от друга, здесь же оба слагаемых можно вычислять в каком угодно порядке - от перестановки слагаемых сумма не изменяется.


Цитата(val @ 9.3.2005, 14:44)
да, на самом деле, правильный ответ именно 117


Не фига. smile Правильный ответ дан выше.

Цитата(val @ 9.3.2005, 14:44)
И как тут возможно корректное портирование?!


Портирование некорректных выражений не может быть корректным никак.



Цитата(Goryachev @ 9.3.2005, 17:28)
Я не понимаю, почему в VC++ и в BC++ дает 47, но по стандартному приоритету операторов, должно быть 117.


Нет тут никакого стандартного приоритета операций. Если я напишу так:
Код

с = (a*b) - (36 / (a=(b+2)) );

или

с = - (36 / (a=(b+2)) )+(a*b);



ничего не измениться.

Добавлено @ 04:01
Цитата(versus @ 9.3.2005, 23:14)
видимо правильно будет не писать такой код вовсе :-)


Именно!

Автор: Mysterio 11.3.2005, 10:22
В книжках пишут,что компилятор(в моем случ.BC311) проходит в два захода. Причем в первом('заход присваивания') приоритеты распределяются по принципу нарастания операций. Т.е. последнее, что он "помнит" есть небольшое выражение a=(b+2) для последующих операций над переменными во втором заходе. И получается именно 117. Насчет VC++ я считаю, что там проходы компилятора организованы несколько иначе. Может кто знает?

Автор: val 11.3.2005, 10:25
Цитата
Цитата (val @ 9.3.2005, 14:44)
да, на самом деле, правильный ответ именно 117



Не фига.  Правильный ответ дан выше.


Нет, товарищи, именно правильный ответ 117. Всё остальное глюки компиляторов. Я проверил на последних версиях DOT NETа и проконсультировался с экспертами по С-спецификации, именно так и есть. Сначала вычисляется всё то, что в самых вложенных скобках и так далее...

Цитата
и никакие приоритеты и скобки (по крайней мере, с точки зрения математики) не могут указать порядка их вычисления


исключительно с точки зрения математики, но ни как разбора выражения компилятором. Еще раз говорю, что первым делом компилятор ставит на исполнение выражение в самых вложенных скобках...


Добавлено @ 10:26
Алгоритм разбора обратной польской записи тому пример...

Автор: Fantasist 11.3.2005, 22:48
Цитата(val @ 11.3.2005, 07:25)
Нет, товарищи, именно правильный ответ 117. Всё остальное глюки компиляторов.


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

Еще тогда попробуй откомпилировать такое выражение:

с = (1*(a*b)) - 36 / (a=(b+2))

Поменяется ли результат? А вот так:

с = -( 36 / (a=(b+2))) +( (1*(a*b)) )

Цитата(val @ 11.3.2005, 07:25)
исключительно с точки зрения математики, но ни как разбора выражения компилятором.


Компилятор должен соотвествовать стандарту языка, если он его выполняет, то все остальное он может делать по своему усмотрению.

Автор: Fantasist 11.3.2005, 23:04
Или еще лучше, возьмем два выражения:

Код

c = 1+2*a*b - 36 / (a=(b+2));

и
Код

c = (1+(2*(a*b))) - 36 / (a=(b+2));


Теперь во втором случае "самые вложенные скобки" - это a*b. Значит по твоему утверждению эти два выражения должны давать разные результаты. Давай скомпилируй и убедись.



Добавлено @ 23:06
Цитата(val @ 11.3.2005, 07:25)
Алгоритм разбора обратной польской записи тому пример...


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


Автор: Fantasist 15.3.2005, 18:07
Ну что, вопросов больше нет? smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)