| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Угадайте, что получиться... |
| Автор: val 9.3.2005, 17:01 | ||
Угадайте с двух раз, какое значение получит переменная с, 47 или 117, после такого вычисления
Сначала подумайте! Будьте честными перед собой и товарищами! Потом я расскажу про проблемы портирования, связанные с этим выражением... |
| Автор: maxim1000 9.3.2005, 17:15 |
| 47 Добавлено @ 17:15 это я так...просто... а вообще, если по-умному, надо бы в стандарт заглянуть... |
| Автор: val 9.3.2005, 17:21 |
| Ну, какие еще варианты? |
| Автор: Enflout 9.3.2005, 17:23 |
| 117 Вычисляем то справа налево вроде. |
| Автор: maxim1000 9.3.2005, 17:25 | ||||||
и действительно, какие же еще могут быть варианты |
| Автор: 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. для интерпретаторов: делаем стек значений и стек операций идем слева направо если встречаем значение (или переменную, которую мы заменяем на ее значение) отсылаем ее в стек значений, если операцию - в стек операций если мы видим, что операция с более низким приоритетом идет после операции с более высоким приоритетом, выполняем ту, которая с более высоким (при этом значения достаются из стека, участвуют в выполнении операции, а результат отправляется назад в стек) со скобками посложнее: у открывающей скобки самый высокий приоритет, у закрывающей - самы низкий это дает такую последовательность: когда доходим до начала выражения в скобках, его значение не будет использовано, пока не будет вычислено до конца когда доходим до конца выражения в скобках, все операции внутри него будут выполнены когда встречаются просто открывающая и закрывающая скобки, они просто схлопываются и остается нужное число фукции реализуются похожим образом, только перед схлопыванием выполняется некоторый код во-о-от... 2. для компиляторов: отличие состоит в том, чтобы как можно больше дел сделать на этапе компиляции и оставить на исполнение минимум операций отсюда получаем: все, что можно посчитать уже сейчас (константы всякие) - посчитать стек операций - убрать, заменив его на простую последовательность операций (которая уже известна) получаем просто код, представляющий из себя три типа операций: 1. записать значение в стек 2. прочитать значение из стека 3. выполнить операцию (арифметическую или функцию) а теперь - как я размышлял, когда отвечал на вопрос: последовательность вычислений такая: 1. a -> стек 2. видим умножение, но не выполняем, т.к. не знаем, что там дальше 3. b -> стек 4. видим "-", значит, умножение надо выполнять 5. a,b <- стек 6. a*b -> стек 7. 36 -> стек 8. видим деление и понимаем: 8.1. вычитание выполнять не стоит, т.к. сначала надо будет выполнить деление 8.2. деление тоже выполнять рановато (т.к. неизвестно, что дальше) 9. видим скобки - радуемся, что не выполнили деление 10. видим функцию operator=( (&a) , (b+2) ) (а вы что думали --. операция &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
источник, если можно... стандарт? если нет, то это все - такие же домыслы, как и то, что я написал
вот мое сообщение - версия ответа на этот вопрос
если портирование соответствует стандарту - оно корректное если нет - то нет другой вопрос: нужно ли корректное портирование или портирование с учетом компилятора исходного кода Добавлено @ 18:01 УЖАС...посмотрел, сколько, оказывается, я написал...УЖАС... |
| Автор: setq 9.3.2005, 18:19 | ||
приоритет операций вещь хорошая, но что выполнится первым: 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 |
| упс-сс |
| Автор: Дрон 9.3.2005, 21:35 | ||||||
А в чём заключается стандартный приоритет операторов? Обычно всё вычисляется слева направо, кроме присваивания и ещё какого-то действия (сейчас в хелпы гляну) Добавлено @ 21:39 Вот: Таблица приоритетов из борландовского хелпа.
Добавлено @ 21:41 Так что я бы сказал, что 47. Добавлено @ 21:44 Насчёт стандартов
|
| Автор: Fixin 9.3.2005, 22:07 | ||
Умножение, потом вычитание деления, так что вполне логично Итак, опять пришел к вопросу "что же правильно?" |
| Автор: versus 10.3.2005, 02:14 |
| видимо правильно будет не писать такой код вовсе :-) |
| Автор: maxim1000 10.3.2005, 11:12 | ||
хм...а почему это знаменатель должен вычисляться раньше? все просто - есть последняя операция - вычитание для ее выполнения нужно посчитать левый аргемент и правый и никакие приоритеты и скобки (по крайней мере, с точки зрения математики) не могут указать порядка их вычисления Добавлено @ 11:12 хоть параллельно |
| Автор: Fantasist 11.3.2005, 03:59 | ||||||||||
| Как и сказал chipset, правильно здесь - undefined behavior. И это по стандарту. То есть компилятор волен выбирать сам, что ему вначале вычислять a*b или (a=b+2). Приоритет играет роль только тогда, когда операции зависимы друг от друга, здесь же оба слагаемых можно вычислять в каком угодно порядке - от перестановки слагаемых сумма не изменяется.
Не фига.
Портирование некорректных выражений не может быть корректным никак.
Нет тут никакого стандартного приоритета операций. Если я напишу так:
ничего не измениться. Добавлено @ 04:01
Именно! |
| Автор: Mysterio 11.3.2005, 10:22 |
| В книжках пишут,что компилятор(в моем случ.BC311) проходит в два захода. Причем в первом('заход присваивания') приоритеты распределяются по принципу нарастания операций. Т.е. последнее, что он "помнит" есть небольшое выражение a=(b+2) для последующих операций над переменными во втором заходе. И получается именно 117. Насчет VC++ я считаю, что там проходы компилятора организованы несколько иначе. Может кто знает? |
| Автор: val 11.3.2005, 10:25 | ||||
Нет, товарищи, именно правильный ответ 117. Всё остальное глюки компиляторов. Я проверил на последних версиях DOT NETа и проконсультировался с экспертами по С-спецификации, именно так и есть. Сначала вычисляется всё то, что в самых вложенных скобках и так далее...
исключительно с точки зрения математики, но ни как разбора выражения компилятором. Еще раз говорю, что первым делом компилятор ставит на исполнение выражение в самых вложенных скобках... Добавлено @ 10:26 Алгоритм разбора обратной польской записи тому пример... |
| Автор: Fantasist 11.3.2005, 22:48 | ||||
Приведи пожалуйста цитаты (или хотя бы параграфы) из стандарта С++(или С), которые бы утверждали, что это выражение должно вычислятся таким образом. Еще тогда попробуй откомпилировать такое выражение: с = (1*(a*b)) - 36 / (a=(b+2)) Поменяется ли результат? А вот так: с = -( 36 / (a=(b+2))) +( (1*(a*b)) )
Компилятор должен соотвествовать стандарту языка, если он его выполняет, то все остальное он может делать по своему усмотрению. |
| Автор: Fantasist 11.3.2005, 23:04 | ||||||
Или еще лучше, возьмем два выражения:
и
Теперь во втором случае "самые вложенные скобки" - это a*b. Значит по твоему утверждению эти два выражения должны давать разные результаты. Давай скомпилируй и убедись. Добавлено @ 23:06
Никакой алгоритм разборе не стандартизирован для использования, а потому использовать компилятор может что хочет. |
| Автор: Fantasist 15.3.2005, 18:07 |
| Ну что, вопросов больше нет? |