Интересный вопрос с зачёта

Интересный вопрос с зачёта

Сообщение User239 » 10 июн 2010, 00:41

Что будет выведено на экран?

#define sqr(x) ((x)*(x));

void main()
{
int y = 5, z = 5;
z = sqr(++y);
printf("%d%d", y, z);
}

Очевидно данный код развернётся в конструкцию z = (++y) * (++y). То есть налицо неопределённое поведение! (undefined behavior)
Говоря простыми словами, изменение переменной в одном и том же выражении дважды.

Стало любопытно, этот ли ответ ожидался от студентов?
User239
 
Сообщения: 45
Зарегистрирован: 23 май 2008, 23:53

Re: Интересный вопрос с зачёта

Сообщение A.Sukhoy » 10 июн 2010, 01:35

Ожидали скорее всего ответа в виде числа.
Потому как вопросы рассчитаны на среднего по уровню студента.
Самое очевидное это 7 и 49.
Если вы конечно ответили так как написано у вас, а вам этот ответ не зачтут (что вполне может быть, потому как работы обычно проверяются по ответам),
то вы вправе наверное оспорить данное решение.

Проверил данный код.
В итоге Keil выдал ответы [7 и 42] и даже [6 и 42] в зависимости от выбранного уровня оптимизации.
Visual Studio выдал 7 и 49 при различных настройках.
Аватара пользователя
A.Sukhoy
 
Сообщения: 182
Зарегистрирован: 08 апр 2008, 17:53

Re: Интересный вопрос с зачёта

Сообщение zhermal » 10 июн 2010, 11:03

Лично пострадал от этого вопроса. :)
Вот ссылка на обсуждение подобной темы, где люди обращаются к стандартам:
http://forum.sources.ru/index.php?showtopic=59178&st=30
zhermal
 
Сообщения: 3
Зарегистрирован: 25 дек 2009, 19:45

Re: Интересный вопрос с зачёта

Сообщение AlexKobyakov » 10 июн 2010, 11:29

Прекрасный пример побочных эффектов от необоснованного использования макросов. Кое-где любят задавать точь в точь такую же задачу, ожидая услышать ответ от User239. :)
AlexKobyakov
 
Сообщения: 81
Зарегистрирован: 05 май 2008, 12:22

Re: Интересный вопрос с зачёта

Сообщение DinKa » 10 июн 2010, 23:43

User239 писал(а):Очевидно данный код развернётся в конструкцию z = (++y) * (++y). То есть налицо неопределённое поведение! (undefined behavior)
Говоря простыми словами, изменение переменной в одном и том же выражении дважды.

А можно все-таки не простыми словами, а до конца и правду. А то получается, как с известной фразой "Религия - опиум для народа", которая является лишь первой половиной настоящей: "Религия - это опиум для народа, она облегчает его страдания."

zhermal писал(а):Лично пострадал от этого вопроса. :)

Вы лично пострадали от того, что вообще пошли не в ту степь в плане объяснения своего ответа на вопрос зачета - Ваше объяснение не имело ничего общего с данной темой обсуждения.
DinKa
 
Сообщения: 247
Зарегистрирован: 23 апр 2008, 18:01

Re: Интересный вопрос с зачёта

Сообщение User239 » 11 июн 2010, 01:03

DinKa писал(а):
User239 писал(а):Очевидно данный код развернётся в конструкцию z = (++y) * (++y). То есть налицо неопределённое поведение! (undefined behavior)
Говоря простыми словами, изменение переменной в одном и том же выражении дважды.

А можно все-таки не простыми словами, а до конца и правду.

Так по-моему всю правду нам поведал A.Sukhoy :)
Результаты запуска кода при использовании разных компиляторов говорят сами за себя.
User239
 
Сообщения: 45
Зарегистрирован: 23 май 2008, 23:53

Re: Интересный вопрос с зачёта

Сообщение zhermal » 11 июн 2010, 08:44

DinKa писал(а):
zhermal писал(а):Лично пострадал от этого вопроса. :)

Вы лично пострадали от того, что вообще пошли не в ту степь в плане объяснения своего ответа на вопрос зачета - Ваше объяснение не имело ничего общего с данной темой обсуждения.

Да, признаться, тогда я вовсе смутился. :)
zhermal
 
Сообщения: 3
Зарегистрирован: 25 дек 2009, 19:45

Re: Интересный вопрос с зачёта

Сообщение Рустам » 11 июн 2010, 09:33

Для меня не очевидным, но самым понятным был вариант 7 42.
Аватара пользователя
Рустам
 
Сообщения: 164
Зарегистрирован: 27 май 2008, 01:24

Re: Интересный вопрос с зачёта

Сообщение Ryukzak » 12 июн 2010, 03:18

Наткнулся вот на такой пост в блоге: http://deepencpp.blogspot.com/2008/06/blog-post.html

Там описано забавное поведение C++ (мне кажется это работает лишь у избранных компиляторов). В принципе пример можно адаптировать в СИ и выдавать студентам. По крайней он определённо способствует пониманию адресной арифметики.
Аватара пользователя
Ryukzak
 
Сообщения: 73
Зарегистрирован: 03 апр 2008, 22:08

Re: Интересный вопрос с зачёта

Сообщение DinKa » 12 июн 2010, 12:59

User239 писал(а):
DinKa писал(а):
User239 писал(а):Очевидно данный код развернётся в конструкцию z = (++y) * (++y). То есть налицо неопределённое поведение! (undefined behavior)
Говоря простыми словами, изменение переменной в одном и том же выражении дважды.

А можно все-таки не простыми словами, а до конца и правду.

Так по-моему всю правду нам поведал A.Sukhoy :)
Результаты запуска кода при использовании разных компиляторов говорят сами за себя.

Это может еще говорить о том, насколько тот или иной компилятор соответствует стандарту языка Си (вопрос еще какому - C89, C99,...). То, что выдает компилятор - следствие реализации языка, похожего на описанный в стандарте - не знаю, кто может гарантировать 100% соответствие (хотя разработчики компиляторов стараются, как могут). Однако больше чудес может встретиться при использовании специализированных компиляторов с расширениями стандарта языка Си для разработки ПО встраиваемых систем, так как это прежде всего связано с архитектурными особенностями программируемых кристаллов + всевозможные опции оптимизации не добавляют ясности. К таким компиляторам как раз относится и уже упомянутый Keil C51.

Однако все выше сказанное имеет косвенное отношение к тому, как следовало ответить на данный вопрос зачета, потому что знаний стандарта языка Си, всех тонкостей, настроек оптимизации абстрактных компиляторов никто не требовал.
Главное: пояснение ответа превалировало над значением самого ответа (это касалось не только данного вопроса).

Мне было интересно узнать полную версию Вашего ответа на основе стандарта, если уж Вы пошли по этому пути - именно стандарт в данном случае объясняет причины неопределенного поведения, а не следствия, соответственно, является правдой. Естественно, такой ответ был бы засчитан, как правильный.
Почему я так борюсь за полный ответ в данной теме? Потому что отсутствие такого ответа вызывает у других читателей темы (в том числе студентов) совершенно противоположный эффект: в любом мало-мальски похожем на данный пример коде им мерещится неопределенное поведение (см. соседнюю тему) - а это заблуждение.
Поэтому обращусь к стандарту на язык C99 (драфт версия).
Список ситуаций, которые приводят к undefined behaviour, занимает не меньше 10 страниц, среди которых есть и эта:
"Если в выражении одна и та же переменная изменяется больше одного раза между двумя точками следования, то возникают побочные эффекты и налицо неопределенное поведение."
Точка следования (sequence point) - любая точка программы, в которой гарантируется, что все побочные эффекты предыдущих вычислений уже проявились, а побочные эффекты последующих еще отсутствуют.
Что является точкой следования? В стандарте перечислены такие:
  • The call to a function, after the arguments have been evaluated.
  • The end of the first operand of the following operators: logical AND && ; logical OR || ; conditional ? ; comma , .
  • The end of a full declarator: declarators;
  • The end of a full expression: an initializer; the expression in an expression statement; the controlling expression of a selection statement (if or switch); the controlling expression of a while or do statement; each of the expressions of a for statement; the expression in a return statement.
  • Immediately before a library function returns.
  • After the actions associated with each formatted input/output function conversion specifier.
  • Immediately before and immediately after each call to a comparison function, and also between any call to a comparison function and any movement of the objects passed as arguments to that call.

Из этого списка следует, что в выражении z = (++y) * (++y) операции ++y НЕ являются точками следования (хотя "++y" эквивалентно выражению "y += 1") :arrow: неопределенная ситуация. С другой стороны, например, в выражении z = (++y) ? (++y); 0 никакой неопределенности нет, т.к. точка следования расположена после первого (условного) выражения.

Другой вариант ответа (если не знать стандарта) - это 749, 742 или другие варианты, если они будут адекватно объяснены.

Третьим вариантом ответа, который мог быть принят, является такой: в жизни так программировать нельзя! + пояснения почему.
Хочу обратить внимание, что данный (и другие) пример кода не является примером программирования в реальных проектах. Это всего лишь учебная задача, охватывающая несколько тем в языке Си, знание которых и проверяется.

Кстати, gcc как и MS Visual Studio тоже выдает результат 749. Именно эти популярные и широко используемые компиляторы для ПК применялись для проверки задач по языку Си в зачете.

Спасибо за такую внимательность и дотошность - учтем в следующие разы и будем, в свою очередь, внимательнее. :good:

Однако хочется сказать следующее:
  1. Большому количеству Ваших однокурсников, обучающихся с Вами по одной учебной программе, сии высокие материи языка Си недоступны, так как они не знают элементарных вещей, более того, не умеют программировать вообще ни на каком языке.
  2. О чем говорит тот факт, что этот вопрос задали Вы - студент, который замечательно работал в семестре и, в результате, не писал этот зачет, - а не те, кто его писали?
DinKa
 
Сообщения: 247
Зарегистрирован: 23 апр 2008, 18:01

Re: Интересный вопрос с зачёта

Сообщение User239 » 13 июн 2010, 14:50

DinKa писал(а):Мне было интересно узнать полную версию Вашего ответа на основе стандарта, если уж Вы пошли по этому пути - именно стандарт в данном случае объясняет причины неопределенного поведения, а не следствия, соответственно, является правдой.

Спасибо за полную версию, я бы примерно так же объяснил :)
Хотя, как Вы знаете, я всегда за практический подход.
User239
 
Сообщения: 45
Зарегистрирован: 23 май 2008, 23:53


Вернуться в Архив "ИУС" (весна 2010)

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2