|
|
  |
фича компиляторв, инкремент переменной |
|
|
|
May 11 2007, 11:25
|

Знающий
   
Группа: Свой
Сообщений: 723
Регистрация: 29-08-05
Из: Березовский
Пользователь №: 8 065

|
На форуме программистов (здесь http://www.rsdn.ru/Forum/?mid=2481623) с пацанами сейчас подняли интересную тему. Думаю, что си-шникам тоже следует остерегаться подобного кода. В двух словах проблема состоит в том, как компилятор должен понимать оператор инкремента.
int i; int x;
i = 5; x = ++i + ++i;
Чему в результате будет равно х ? Прикол в том, что MS VC++ 6.0 и VC++.NET дают результат, равный 14. Майкрософтовский C# и IAR говорят, что х = 13. А более всего удивил Watcom -- у него результат зависит от того, включена-ли оптимизация или нет... Я, конечно, понимаю, что код, который обсуждается, несколько далек от жизни, но все же, знать о таких прибабахах -- надо. Вечером дома, попробую еще в CodeVision эту фичу покрутить.
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
May 11 2007, 11:29
|
Участник

Группа: Новичок
Сообщений: 70
Регистрация: 27-03-07
Пользователь №: 26 533

|
Тут все просто. По стандарту результат исполнения такого кода не определен. Тот, кто пишет такой код - сам себе злобный буратино.
|
|
|
|
|
May 11 2007, 11:57
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(zhevak @ May 11 2007, 14:25)  как компилятор должен понимать оператор инкремента. Понимать он должен правильно  В данном выражении префиксные инкременты имеют максимальные приоритеты, посему формально при тупом исполнении 14, но выражение глупозапутанное и как раз тот случай, когда оптимизаторы 'ломаются'  . Просто так писать не надо! И насчет слова 'оптимизация' - она очень разная бывает, у меня, например, Watcom при включении в проект со вполне любовно подобранной оптимизацией без вопросов выдал 14. A IAR честно предупредил, что не понимает такой хрени и за результат не ручается.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 11 2007, 12:39
|
Участник

Группа: Новичок
Сообщений: 70
Регистрация: 27-03-07
Пользователь №: 26 533

|
не страдайте фигней. Вот вам выдержка из стандарта С++ i = ++i + i //the behavior is unspecified
|
|
|
|
|
May 11 2007, 12:42
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(vromanov @ May 11 2007, 15:39)  не страдайте фигней. Вот вам выдержка из стандарта С++ i = ++i + i //the behavior is unspecified Смотрим внимательно и находим одно отличие: Код i= ++i + i; x= ++i + i;
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 11 2007, 12:51
|
Участник

Группа: Новичок
Сообщений: 70
Регистрация: 27-03-07
Пользователь №: 26 533

|
Как любителю стандартов, вам надо было не искать отличия, а пойти почитать стандарт. Там написано, что при наличии сторонних эффектов но описанных в стандарте поведение не определено. Тут как раз имеем сторонний эффект не описанный в стандарте.
|
|
|
|
|
May 11 2007, 15:37
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(vromanov @ May 11 2007, 15:29)  Тут все просто. По стандарту результат исполнения такого кода не определен. Тот, кто пишет такой код - сам себе злобный буратино. Угу Цитата Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression. Furthermore, the prior value shall be read only to determine the value to be stored.70) Цитата If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint is violated, the behavior is undefined. Цитата 1 undefined behavior behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements 2 NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). В выражении ++i + ++i значение i изменяется два раза, следовательно, по стандарту результат неопределенный. В выражении ++i + i значение i считывается два раза, один раз для вычисления нового сохраняемого значения i слева, второй раз - при вычислении правой части сложения, следовательно, по стандарту результат неопределенный. Обратите внимание, что ключевой момент для применения правила об одном считывании - значение переменной i модифицируется в выражении.
--------------------
Пишите в личку.
|
|
|
|
|
May 11 2007, 17:48
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 11 2007, 18:37)  В выражении ++i + i .... Таки да! Имеет место быть неопределенность исполнения side effect от оператора ++ по отношению к операции сложения. Взгляд замылил префиксный инкремент  , который на самом деле не имеет отношения к делу. Если вернуться к первоисточнику, то в этом конкретном случае ничего принципиально не разрешимого для компилятора нет, однако смягчения правил игры установленные стандартом в виде виде sequence point позволяют ему не разбираться с этими заморочками. Совершенно правильный подход к делу, поскольку заумные выражения усложняет жизнь компилятору и на самом деле ничего не дают програмисту. С другой стороны никто не может запретить разбирать и более сложные конструкции в этом случае он (Watcom, например) спокойно жует и такие перлы и выдает правильное значение 14. Те компиляторы, которые не разбирают - ругаются (IAR). Те компиляторы, которые не разбирают, молчат и выдают произвольное значение - бяки  . Цитата(vromanov @ May 11 2007, 19:08)  Удивительно, что столь очевидная вещь собрала столько сломанных копий. Где Вы копья увидели? А вещь не очевидная, если считать очевидным не использование такой дури в явном виде ни при каких условиях  .
Сообщение отредактировал zltigo - May 11 2007, 18:52
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 11 2007, 18:54
|
Участник

Группа: Новичок
Сообщений: 70
Регистрация: 27-03-07
Пользователь №: 26 533

|
Цитата(zltigo @ May 11 2007, 21:48)  Где Вы копья увидели? А вещь не очевидная, если считать очевидным не использование такой дури в явном виде ни при каких условиях  . По всем сообществам разбирают эту строчку. И куча народа дже после правильного ответа продолжают что-то придумывать, строить какие-то предположения.. Еще и колеги на работе по аське достали этим выражением.
|
|
|
|
|
May 11 2007, 19:57
|

Частый гость
 
Группа: Свой
Сообщений: 163
Регистрация: 22-06-06
Из: Киев
Пользователь №: 18 292

|
Цитата(vromanov @ May 11 2007, 20:08)  Удивительно, что столь очевидная вещь собрала столько сломанных копий. Есть кучу куда более прикольных особеностей в с++  //-------------------------------------- Когда-то полдня убил на глюк ИАРА. Код ниже работал в MCС18 (пик), а в ИАРЕ (4.30, ARM) нет. unsigned char c; char* cr; выше инициализация credential; while((c = *credential) != '\r') // Advance until \r (end of credentials) credential++; *credential = '\0'; // NULL char to replace \r. //--------------------------- Пока не заменил на: do { if(*credential=='\r') break; credential++; }while(1); credential++; *credential = '\0'; // NULL char to replace \r. Причем игрался с оптимизациями - не помогало. Вылетало за пределы массивов.
Сообщение отредактировал lebiga - May 11 2007, 20:01
|
|
|
|
|
May 11 2007, 20:02
|
Участник

Группа: Новичок
Сообщений: 70
Регистрация: 27-03-07
Пользователь №: 26 533

|
Цитата(zltigo @ May 11 2007, 23:03)  Никаких придумок - либо компилятор должен выдать 14, либо ссылаясь на биль о правах компиляторов отказаться отвечать на этот вопрос допущения стандарта послать такое выражения подальше. Компилятор ничего не должен.. В стандарте не написано, что он должен посылать такое выражение. Цитата(lebiga @ May 11 2007, 23:57)  //--------------------------------------
Когда-то полдня убил на глюк ИАРА. Код ниже работал в MCС18 (пик), а в ИАРЕ (4.30, ARM) нет. А вот это уже 100% глюк компилятора. Точнее оптимизатора.
|
|
|
|
|
May 11 2007, 20:19
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(vromanov @ May 11 2007, 23:02)  Компилятор ничего не должен.. В стандарте не написано, что он должен посылать такое выражение. Нет, если он взялся разбирать это выражение, то он должен руководствуясь общими правилами выполнения операций и их приоритетов выдать такое значение. А вот отказаться имеет право и в случае отказа естествено не должен ничего и ни кому. Цитата(Oldring @ May 11 2007, 22:59)  IMHO правильное значение может быть 12, 13, но никак не 14.  Выполняется инкремент i, как самый приоритетный (левый или правый на Ваше усмотрение  ) Затем второй инкремент i, потом сложение, как самая неприоритетная операция. Выполнены все три операции в порядке приоритетов. Все.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 11 2007, 21:07
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 12 2007, 00:19)  Нет, если он взялся разбирать это выражение, то он должен руководствуясь общими правилами выполнения операций и их приоритетов выдать такое значение. А вот отказаться имеет право и в случае отказа естествено не должен ничего и ни кому. http://electronix.ru/forum/index.php?s=&am...st&p=249062Цитата Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Это цитата из стандарта. На русский переводить не нужно? Как видите, компилятор никому ничего не должен, все остальное - фантазии. Цитата(zltigo @ May 12 2007, 00:19)  Выполняется инкремент i, как самый приоритетный (левый или правый на Ваше усмотрение  ) Затем второй инкремент i, потом сложение, как самая неприоритетная операция. Выполнены все три операции в порядке приоритетов. Все. Да, именно так. Пусть аргументы '+' вычисляются справа налево  Сначала считывается значение правого i (5) прибавляем 1, записываем значение правого i. Запоминаем результат правого подвыражения (6). Затем считываем значение левого i (6), прибавляем 1, сохраняем новое значение i, запоминаем результат левого подвыражения (7). Теперь к результату правого подвыражения (6) прибавляем результат левого подвыражения (7) и в результате получаем 13. Альтернатива - когда результаты преинкремента прописываются в переменные в конце вычисления выражения (имеют право - точка сохранения результатов однозначно не определена). В этом случае результат двух подвыражений будет 6, и их сумма будет 12. А вот как получить 14 - не понимаю
--------------------
Пишите в личку.
|
|
|
|
|
May 11 2007, 21:57
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 12 2007, 00:07)  Это цитата из стандарта. На русский переводить не нужно? Как видите, компилятор никому ничего не должен, все остальное - фантазии. Переводить не нужно. Может вам мой предыдущий пост на английский перевести? Или постараетесь мой русский язык понять? Повторять не вижу смысла. Цитата Запоминаем результат правого подвыражения (6) Вот 'запоминаем' это и есть чистейшей воды фантазии. С какого бодуна компилятор будет заводить промежуточную переменную-дубль для запоминания? Только если у него совсем крышу снесло. Цитата Альтернатива - когда результаты преинкремента прописываются в переменные в конце вычисления выражения (имеют право - точка сохранения результатов однозначно не определена). В этом случае результат двух подвыражений будет 6, и их сумма будет 12. Это или инкремент суммирование инкремент суммы с тем-же результатом - имеет право, только если это он сделает без warnig я не пойму такой поступок. Цитата А вот как получить 14 - не понимаю  Тогда перечитайте, вдруг поймете. Если не поймете - можете поискать компилятор, который без warning выдаст результат отличный от 14. Может удастся принять, как даденность  . Вдруг найдете - сообщите, что-бы вдруг я случайно не стал пользовать небрежно писанный компилятор.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 12 2007, 07:23
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 12 2007, 01:57)  Переводить не нужно. Может вам мой предыдущий пост на английский перевести? Или постараетесь мой русский язык понять? Повторять не вижу смысла. А что - переведите, будет любопытно.  Вот только это все равно будет Ваше личное мнение, пусть и на английском языке, в отличие от процитированных мною требований стандарта. Цитата(zltigo @ May 12 2007, 01:57)  Вот 'запоминаем' это и есть чистейшей воды фантазии. С какого бодуна компилятор будет заводить промежуточную переменную-дубль для запоминания? Только если у него совсем крышу снесло. По правилам формальной семантики выражений языка С (так как мы говорим о "правильности" выражений - мы на время забываем, что такое выражение в целом - undefined bihavior). '+' суммирует результаты своих левого и правого подвыражений. С какого бодуна результат первого подвыражения изменяется после его вычисления? Цитата(zltigo @ May 12 2007, 01:57)  Тогда перечитайте, вдруг поймете. Если не поймете - можете поискать компилятор, который без warning выдаст результат отличный от 14. Может удастся принять, как даденность  . Вдруг найдете - сообщите, что-бы вдруг я случайно не стал пользовать небрежно писанный компилятор. Я-то как раз понимаю, как компилятор получает такой результат. У многих компиляторов один из промежуточных этапов компиляции - получение трехадресного кода. При этом разработчики компиляторов, помня правило, процитированное мною первым в первом моем посте, полагаются на то, что переменная i второй раз в одном и том же выражении не изменится, и в ней можно сохранить промежуточный результат подвыражения вместо заведения еще одной промежуточной переменной. Такое предположение компилятора в данном случае является ошибочным. То есть такое поведение - побочный эффект, допускаемый стандартом как undefined bihavior, но никак не "правильное" поведение компилятора.  P.S. Что касается "небрежно написанных компиляторов" - есть такая русская пословица, про зеркало. Компилятор может выдавать что угодно в подобных выражениях. Делать или нет специальный анализ выражения для генерации предупреждений в таких случаях - это выбор разработчиков компиляторов, тем более, что во многих случаях (с указателями) компилятор просто не может знать, что два подвыражения модифицируют один объект. Поэтому лучше так не пишите, а если пишите - то ничего не требуйте от компилятора. Язык С, действительно, налагает довольно высокие требования на квалификацию программиста в части неиспользования некоторых конструкций.
--------------------
Пишите в личку.
|
|
|
|
|
May 12 2007, 08:31
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 12 2007, 10:23)  Я-то как раз понимаю, как компилятор получает такой результат.... Я тоже. Только это внутреннее дело компилятора, как он обрабатывает неправильные с точки зрения стандарта (определяющего минимальные требования к компилятору) конструкции. То, что k=++i + ++i; компилятор имеет право не заморачиваясь на специальные анализы тупо на автомате разбирать и получать непредсказуемый результат это понятно. И никто никогда против этого не возражал. То, что разработчики компиляторов имеют право не прикрываясь минимальными требования стандарта разбирать более сложные выражения, надеюсь не вызывает Вашего категорического непрятия? Впрочем, если и вызывает, то пожалуй с этим разработчики компиляторов могут не согласиться  . Выражение k=++i + ++i; являсь совершенно диким, тем не менее поддается однозначной разборке согласно основополагающим правилам операций и их приоритетов. Про трудности компиляции такого и _правильное_ решение стандарта разрешить не заморачиваться с такой разборкой все ясно. Цитата Что касается "небрежно написанных компиляторов" - есть такая русская пословица, про зеркало. Это не ко мне. Я не писал, не пишу и не буду писать подобных выражений, но тем не менее, если вдруг комилятор позволит себе не выдав предупреждение в таком выражении выдать значение отличное от 14, то это меня насторожит и приведет к некоторому недоверию к такому компилятору, поскольку он чего-то не поняв позволил себе меня не предупредить. Цитата Делать или нет специальный анализ выражения для генерации предупреждений в таких случаях - это выбор разработчиков компиляторов Это их право. Только у меня тоже есть право  не использовать такие компиляторы  . Поскольку сегодня выходной день, то я провел маленький тест используемых мною в повседневной жизни компиляторов. OpenWatcom, GCC, Borland не возразили и выдали правильный результат. IAR, VisualDSP - выдали предупреждение. Все это с учетом того, что warnigs я всегда по максимуму активизирую и без оптимизации компиляцию не пользую. Результат меня полностью удовлетворил - по поводу разборки этой дури у меня претензий к используемым мною компиляторам нет и с их разработчиками у меня коннсенсус  . Цитата Поэтому лучше так не пишите, а если пишете - то ничего не требуйте от компилятора. К чему это адресное обращение? Я призывал так писать??? P.S. Пожалуй по четвертому кругу я больше не пойду изъясняться по проблемам k=++i + ++i;
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 12 2007, 08:45
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 12 2007, 12:31)  Выражение k=++i + ++i; являсь совершенно диким, тем не менее поддается однозначной разборке согласно основополагающим правилам операций и их приоритетов. Про трудности компиляции такого и _правильное_ решение стандарта разрешить не заморачиваться с такой разборкой все ясно. Ну так приведите свой правильный разбор. Я свой привел, приводящий к 12 или 13. Я утверждаю, что 14 - это неправильный результат исходя из семантики операций. Цитата(zltigo @ May 12 2007, 12:31)  К чему это адресное обращение? Я призывал так писать??? В ответ на Ваше утверждение, что для Вас имеет принципиальное значение, какой результат выдается для этого выражения. Если я Вас неправильно понял - тогда извините.
--------------------
Пишите в личку.
|
|
|
|
|
May 12 2007, 09:26
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 12 2007, 11:45)  Ну так приведите свой правильный разбор. Я приводил. Цитата Я свой привел, приводящий к 12 или 13. Приводили, но не с точки зрения базовых правил а с точки зрения как может быть построена разборка выражения в потрохах компилятора. Что позволяет объяснить, почему появляется неправильный результат и почему стандарт не требует разбирать такую ерунду. Но все это не имеет отношения к пользователю компилятора написавшего дурацкое, сложно разбираемое компилятором (если он за это возьмется!), хреново оптимизируемое и трудно понимаемое человеком, но вполне однозначо трактуемое выражение - "берем одну едиственную переменную, инкрементируем один раз, инкрементируем второй раз, прибавляем к ней ее-же значение. Цитата В ответ на Ваше утверждение, что для Вас имеет принципиальное значение, какой результат выдается для этого выражения. Если я Вас неправильно понял - тогда извините. Про "принципиальное значение" я ни сном ни духом не поминал. Повторяю - выдаваемый результат лично для меня имеет некоторое (а отнюдь не принципиальное) значение только в плане оценки компилятора и только в том единственном случае, когда он не выдав предупреждения выдал результат отличный от 14. В проведенных тестах я даже не смотрел на результат у компиляторов которые выдали warning-и. Во настолько он для меня имеет "принципиальное значение"  Извиняю.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 12 2007, 09:56
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 12 2007, 13:36)  Жаль. То есть ссылку на свой пост, про который Вы утверждаете, что там описали формальный разбор выражения, Вы привести не можете? Цитата(zltigo @ May 12 2007, 13:26)  Приводили, но не с точки зрения базовых правил а с точки зрения как может быть построена разборка выражения в потрохах компилятора. Что позволяет объяснить, почему появляется неправильный результат и почему стандарт не требует разбирать такую ерунду. Но все это не имеет отношения к пользователю компилятора написавшего дурацкое, сложно разбираемое компилятором (если он за это возьмется!), хреново оптимизируемое и трудно понимаемое человеком, но вполне однозначо трактуемое выражение - "берем одну едиственную переменную, инкрементируем один раз, инкрементируем второй раз, прибавляем к ней ее-же значение. Нет, грамматические и семантические правила - это часть стандарта языка, а не реализации конкретного компилятора. Я ссылался на грамматические правила и на семантику операций. Выражение x = ++i + ++i; должно быть грамматически разобрано следующим образом (запись дерева - стандартная префиксная) Код assign( addr( 'x' ), sum( assign( addr( 'i' ), add( value( addr( 'i' ) ), 1 ) ), assign( addr( 'i' ), add( value( addr( 'i' ) ), 1 ) ) ) ) Как при аккуратном исполнении этого дерева разбора в соответствии с семантическими правилами языка можно получить 14 - не понимаю. P.S. Если придираться - в этом дереве уже расрыта операция ++i как эквивалентная (i+=1).
--------------------
Пишите в личку.
|
|
|
|
|
May 12 2007, 10:16
|

Гуру
     
Группа: Модераторы
Сообщений: 2 095
Регистрация: 27-08-04
Из: Россия, СПб
Пользователь №: 553

|
По моему все очень просто, т.к. код архитектурно зависимый. Даже считая по дереву: Код 1. *i=*i+1;[6] 2. *i=*i+1;[7] 3. x=i+i;[14] С другой стороны, результат в java(как в стековой архитектуре). Код 1. i=i+1[6] 2. push 3. i=i+1[7] 4. push 5. add[13] Все прозрачно)))
|
|
|
|
|
May 12 2007, 10:21
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(vetal @ May 12 2007, 14:16)  3. x=i+i;[14][/code] Все прозрачно))) Так вот откуда взялась эта третья операция - x = i + i? Как она получена из дерева разбора выражения? P.S. ++i эквивалентно i += 1. Цитата An assignment expression has the value of the left operand after the assignment, but is not an lvalue.
--------------------
Пишите в личку.
|
|
|
|
|
May 12 2007, 10:42
|

Гуру
     
Группа: Модераторы
Сообщений: 2 095
Регистрация: 27-08-04
Из: Россия, СПб
Пользователь №: 553

|
Цитата Так вот откуда взялась эта третья операция - x = i + i? Как она получена из дерева разбора выражения? В дереве ясно написано x=add {++i,++i}, т.е. сначала выполняются все преинкрементом, а затем выполняется операция сложения. Т.к. операции преинкремента выполняются с одной ячейкой памяти - происходит увеличение ячейки на 2. Операция сложения складывает 2 ячейки памяти с адресом &i, т.е. как и написано в коде. Это вполне справедливо при рассмотрении x86 как машины с памятью, которой она и является))) Я не могу спрогнозировать результат только на регистровой машине(классической или как при представлении x86 в регистровом эквиваленте), т.к. неопределенность будет зависеть от результата оптимизации. На регистровой машине будут справедливы 2 подхода : -неоптимизированный (по первичному графу) получится как в x86, т.к. сначала выполнятся все "пре" операции и получится результат как в машине с памятью; -оптимизированный, когда все будет делаться на лету и максимальным использованием регистров код может выглядеть как Код ldw r1, i add r1,r1,1 stw i, r1; можно исключить mov r2,r1 add r2,r2,1 stw i,r2 add r3,r1,r2
|
|
|
|
|
May 12 2007, 10:52
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(vetal @ May 12 2007, 14:42)  В дереве ясно написано x=add {++i,++i}, т.е. сначала выполняются все преинкрементом, а затем выполняется операция сложения. Т.к. операции преинкремента выполняются с одной ячейкой памяти - происходит увеличение ячейки на 2. Операция сложения складывает 2 ячейки памяти с адресом &i, т.е. как и написано в коде. Это вполне справедливо при рассмотрении x86 как машины с памятью, которой она и является))) Не совсем - в дереве ясно написано, что нужно сложить результат первого подвыражения и результат второго подвыражения. Если бы результат подвыражений был lvalue - тогда при вычислении сложения нужно было бы взять у lvalue (неформально - ссылки на объект) значение объекта, и тогда можно было бы прочитать из переменной i результат, отличный от приписанного в i в подвыражении, если бы преобразование lvalue в значение выполнялось после вычисления обоих подвыражений как преобразование типа для операции '+'. Но так как результат вычисления подвыражения lvalue не является - мы не имеем права считывать его обратно из i и обязаны использовать именно то значение, которое было вычислено соответсвующим подвыражением. Одно из подвыражений всегда даст 6, в каком бы порядке ни выполнять операции. Что происходит в реальных компиляторах - вполне понятно, это не вопрос. Речь шла про "правильность", причем, после закрывания глаз на то, что такое выражение в целом имеет undefined bihavior.
--------------------
Пишите в личку.
|
|
|
|
|
May 12 2007, 12:23
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(vetal @ May 12 2007, 15:11)  Потому и "undefined bihavior", что по моему мнению оператор + складывает 2 ячейки памяти с адресом I, а по вашему он заводит дополнительную переменную. Тут всё и кроется)) undefined bihavior - потому что часто зависит, например, от порядка вычисления подвыражений, да и для свободы оптимизатора полезно, когда побочные эффекты можно вычислять в произвольном порядке. Ваше мнение о том, "что оператор + складывает 2 ячейки памяти с адресом i" противоречит утверждению из стандарта, что результат вычисления ++i не есть lvalue. Так что такую интерпретацию принять не могу как "правильную"  Цитата(zltigo @ May 12 2007, 15:48)  Вся эта бодяга действительно отдана на откуп компилятору в зависимости от платформы. Но что интересно - в результате реального эксперимента все компиляторы для x86 платформы выдали тот самый результат, а под ARM и BF выдали warning - не смогли на штатном механизме обеспечить? Интересный такой нюанс. Надо будет GNU на не на x86 платформе спытать. arm-elf-gcc версии 4.1.1 выдает 13.
--------------------
Пишите в личку.
|
|
|
|
|
May 12 2007, 13:14
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 12 2007, 17:05)  Молча? По умолчанию - да. В программе, приведенной ниже, с ключем -Wsequence-point выдается предупреждение "warning: operation on 'i' may be undefined" внутри main(), но не внутри f(). В обоих случаях - 13. Код int f( int* p1, int* p2 ) { return ++(*p1) + ++(*p2); }
int main( void ) { int i; int x1, x2;
i = 5; x1 = ++i + ++i;
i = 5; x2 = f( &i, &i );
return x2; } P.S. С включенной оптимизацией -O3 main своится к возврату 13.
--------------------
Пишите в личку.
|
|
|
|
|
May 12 2007, 14:14
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 12 2007, 16:14)  В программе, приведенной ниже, с ключем -Wsequence-point выдается предупреждение "warning: operation on 'i' may be undefined" внутри main(), но не внутри f(). В обоих случаях - 13. Ну про f() это естественно правильно - по другому было-бы крайне странно. С main() выдал warning расписавшись в непонятках - тоже каой-же после этого спрос. Зксперименировал для начала с OpenWatcom... Цитата P.S. С включенной оптимизацией -O3 main своится к возврату 13. Аналогично. C приличными оптимизациями все сводится к  Код push 0000000eH push offset FLAT:L$402 call near ptr FLAT:printf_ add esp,00000008H ret Пришлось извне передавать. Код void dummy( int i ) { int k = ++i + ++i; printf( "k=%i\r", k ); } Это вариант с разнообразными оптимизаторами: Код add eax,00000002H add eax,eax push eax push offset FLAT:L$402 call near ptr FLAT:printf_ add esp,00000008H ret и вообще без оптимизации: Код push 00000030H call near ptr FLAT:__CHK push ebx push ecx push edx push esi push edi push ebp mov ebp,esp sub esp,0000000cH mov dword ptr -0cH[ebp],eax inc dword ptr -0cH[ebp] inc dword ptr -0cH[ebp] mov eax,dword ptr -0cH[ebp] add eax,dword ptr -0cH[ebp] mov dword ptr -4H[ebp],eax push dword ptr -4H[ebp] mov eax,offset FLAT:L$450 push eax call near ptr FLAT:printf_ add esp,00000008H mov esp,ebp pop ebp pop edi pop esi pop edx pop ecx pop ebx ret Но при любых уровнях оптимизации "неизменно превосходный результат". warnin-ов нет. Причем, что действительно интересно даже в вырожденном случае с тупым возвратом значения , где уже все заранее решено - 14. Цитата(vetal @ May 12 2007, 16:09)  И говорит что так делать нельзя. В обоих случаях оптимизации говорит нельзя?
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 12 2007, 14:51
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 12 2007, 17:38)  В любом случае, это не есть доказательство "правильности" значения 14. Ну скажем так, это некий результат полученный на нескольких компиляторах, без сопутствующего warning (типа не сомневались в результате?). Все другие компиляторы выдающие отличный результат неизменно генерили при этом warning. Как это можно истолковать? А с учетом того, что авторы компиляторов разбираюся в этом скорее всего лучше, чем все здесь собравшиеся вместе взятые? Цитата gcc на x86 неизменно возвращает 14. в том числе, из f()  Я мельком глянул на f() - естественно ошибся  .
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 12 2007, 15:14
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 12 2007, 18:51)  Ну скажем так, это некий результат полученный на нескольких компиляторах, без сопутствующего warning (типа не сомневались в результате?). Все другие компиляторы выдающие отличный результат неизменно генерили при этом warning. Как это можно истолковать? А с учетом того, что авторы компиляторов разбираюся в этом скорее всего лучше, чем все здесь собравшиеся вместе взятые? Как истолковать? Как невыдачу предупреждения на undefined bihavior код.  То, что "А с учетом того, что авторы компиляторов разбираюся в этом скорее всего лучше, чем все здесь собравшиеся вместе взятые" - утверждение просто смешное. Компилятор - не такая уж непостижимая для понимания программа. Очень много народу писало разнообразные компиляторы - ну разве что не такие оптимизирующие. Вы никогда не читали учебники по устройству компиляторов? Вот, например, из недавних был издан на русском языке в 2001 году. "Компиляторы. Принципы, технологии, инструменты". Ахо, Сети, Ульман. Авторы, кстати - классики по теории компиляции. Очень рекомендую.
--------------------
Пишите в личку.
|
|
|
|
|
May 12 2007, 15:42
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 12 2007, 18:14)  Как истолковать? Как невыдачу предупреждения на undefined bihavior код.  И при этом выдачу предупреждения при компиляции компилятором из этой-же линейки для другой платформы  ??? И выдачу предупреждения undefined bihavior этим-же компилятром для другого выражения? И все это с грубыми, по Вашему мнению нарушениями? Цитата Компилятор - не такая уж непостижимая для понимания программа. Компилятор вполне постижимая - сам писал в свое время со своего-же тестового языка  для Z80 target. Проблема здесь в толковании правил и обеспечении соблюдения неписанных договоренностей.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 12 2007, 16:06
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 12 2007, 19:42)  И при этом выдачу предупреждения при компиляции компилятором из этой-же линейки для другой платформы  ??? И выдачу предупреждения undefined bihavior этим-же компилятром для другого выражения? И все это с грубыми, по Вашему мнению нарушениями? Компилятор вполне постижимая - сам писал в свое время со своего-же тестового языка  для Z80 target. Проблема здесь в толковании правил и обеспечении соблюдения неписанных договоренностей. Я считаю, что все, что касается правил компиляции - изложено в стандарте языка. Там нет ничего непостижимого. Стандарт - это закон. Поэтому доводы "это непостижимо" не приемлю, извините. Я Вам привел цитаты из стандарта и разъяснил, как именно значение 14 противоречит понятию "правильности" результата этого выражения если даже забыть на время об ограничении по поводу undefined bihavior для выражения в целом. Вы можете привести какие-либо аргументы в поддержку своей позиции (утверждений об "однозначности разбора" и о "правильности" результата 14) кроме того, что некоторые космпиляторы не выдают предупреждение, выдавая в результате 14? Ну и кроме того, хочу привести последний аргумент. То, что часть компиляторов выдает 13 (имеют полное право), а часть - 14, не означает ли, что компиляторы, не выдающие на такой код предупреждение, просто имеют более слабую диагностику по сравнению с теми, которые выдают такую диагностику?
--------------------
Пишите в личку.
|
|
|
|
|
May 12 2007, 16:29
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 12 2007, 19:06)  Стандарт - это закон. Поэтому доводы "это непостижимо" не приемлю, извините. Закон. Только закон (хоть "компиляторный" хоть "человеческий" ) все не описывает и уж точно не все описывает понятно. Отсюда и профессиональные писатели компиляторов и профессиональные адвокаты. И уж тем более закон не запрещает разбирать компиляторам более сложные случаи. Вот и получаем, те которые разбирают и не жалуются на непонятливость те выдают 14. Цитата Ну и кроме того, хочу привести последний аргумент. Это хорошо-бы  а то ходим уже по мамнадцатому кругу  Цитата То, что часть компиляторов выдает 13 (имеют полное право), а часть - 14, не означает ли, что компиляторы, не выдающие на такой код предупреждение, просто имеют более слабую диагностику по сравнению с теми, которые выдают такую диагностику? Может и быть, но! Повторяю неудобные вопросы на которые нет ответов: B при этом, те которые 14 - все как один не выдают warnings, а те которые 13 все напротив - выдают. Случайность? Компилятор одной линейки для одной платформы без warnings выдает 14 а для другой с warnings и 13. Случайность? Поведение с 14 позволяют себе минимум 4 весьма распространенных компилятора. Случайнось? Не слишком-ли много неумелых толкователей закона среди писателей компиляторов? P.S. Пат.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 12 2007, 16:57
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 12 2007, 20:29)  Закон. Только закон (хоть "компиляторный" хоть "человеческий" ) все не описывает и уж точно не все описывает понятно. Отсюда и профессиональные писатели компиляторов и профессиональные адвокаты. Мне-то в этом законе все совершенно понятно. Это Вы почему-то жалуетесь, что там что-то непонятно написано. А по-моему, все совершенно четко. Логика есть логика.  Кстати, Вы так и не показали, как аккуратно исполняя дерево грамматического разбора обсуждаемого выражения можно получить 14.  Цитата(zltigo @ May 12 2007, 20:29)  Может и быть, но! Повторяю неудобные вопросы на которые нет ответов: B при этом, те которые 14 - все как один не выдают warnings, а те которые 13 все напротив - выдают. Случайность? Компилятор одной линейки для одной платформы без warnings выдает 14 а для другой с warnings и 13. Случайность? Поведение с 14 позволяют себе минимум 4 весьма распространенных компилятора. Случайнось? Не слишком-ли много неумелых толкователей закона среди писателей компиляторов?
P.S. Пат. arm-alf-gcc с опциями по умолчанию тоже никаких предупреждений не выдает, компилируя в 13. Нужно продолжать опровержения Вашего утверждения про заговор писателей компиляторов? P.S. Это не пат, это мат.
--------------------
Пишите в личку.
|
|
|
|
|
May 12 2007, 17:55
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 12 2007, 19:57)  arm-alf-gcc с опциями по умолчанию тоже никаких предупреждений не выдает, Меня не интересует работа компиляторов с подавленными warnings, даже если они собраны кем-то по умолчанию. Цитата Нужно продолжать опровержения Вашего утверждения про заговор писателей компиляторов? Нет, по причине того, что Вы уже многократно однообразно повторяетесь. Не отвечая на встречные вопросы. Если что-то новенькое - пишите всенепременнейше! Цитата P.S. Это не пат, это мат.  Можете про себя считать, как угодно. Я это переживу  .
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 12 2007, 22:53
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Я Вам не помешаю ?  Выскажу свое ИМХО: - Компилятор который не выдет warning в такой ситуации, вне зависимости от уровня оптимизации, это компилятор который не следует стандарту С. - соглашусь с Oldring, 12 или 13 еще как-то укладывается в то, как учитывая стандарт С, компилятор должен был бы разбирать это выражение - результат 14 для большинства компиляторов говорит только о том, что "очень хотелось соптимизировать" и компилятор "успешно" справился с этой задачей... 2 zligoЕсли Вы имеете в виду такую предсказуемость работы "оптимизаторов" в компиляторах, то с Вами я тоже полностью согласен
|
|
|
|
|
May 13 2007, 08:35
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 12 2007, 21:55)  Меня не интересует работа компиляторов с подавленными warnings, даже если они собраны кем-то по умолчанию. А с отсутствующими - интересует  Цитата(zltigo @ May 12 2007, 21:55)  Нет, по причине того, что Вы уже многократно однообразно повторяетесь. Не отвечая на встречные вопросы. Если что-то новенькое - пишите всенепременнейше! Что-то новенькое? По поводу "часть компиляторов выдает ворнинги, а часть нет" - отвечать не могу в принципе. Не понимаю логику вопроса. Я почему-то в ходе этого спора вспомнил нумерологию. Я ведь тоже не могу опровергнуть утверждение про несчастливость числа 13. Других встречных вопросов не видел. Ключевой метод для признания "правильности" вычисления выражения - вычисление выражения по грамматическому дереву в соответствии с семантическими правилами. Операция за операцией. Чтобы получить 14 нужно обязательно рассматривать результат ++i как lvalue. По крайней мере, в ANSI C-99 он не lvalue, следовательно, число 14 не может претендовать на правильность. Вы почему-то это ключевое логическое утверждение проигнорировали. Цитата(zltigo @ May 12 2007, 21:55)  Можете про себя считать, как угодно. Я это переживу  . Это здорово. Не обижайтесь - мне само выражение понравилось. Ничего личного. Цитата(zltigo @ May 13 2007, 10:48)  Нет этим однозначно объяснить не получается. Посмотоите результаты реального OpenWatcom, три из многочисленных вариантов (от полной заоптимизированности в банальный возврат 14, до тупого кода при полностью отключенной оптимизации) приводил выше - без разницы. Последовательность действий при этом совершенно не изменялась - решене было приято уже ДО оптимизатора. Я совершенноуже запутался в версиях компиляторов, на которые Вы ссылались. Замечу только, что действия по оптимизации могут предприниматься и без оптимизатора - на этапе порождения внутреннего представления по грамматическому дереву, или на этапе кодогенерации. Как попытка использовать систему команд процессора эффективно. Ключевое отличие x86 от ARM - именно в системе команд. в ARM нет операций АЛУ с аргументами в памяти. В системе команд x86 таких операций море, причем, они широко используются для обхода затычки с регистрами. Поэтому на x86 выгоднее рассматривать результат ++i как находящийся в самой ячейке памяти переменной i, хоть он и не lvalue, потому что ошибка может возникнуть только в выражениях с undefined bihavior. Кстати, если определить i как volatile - в gcc для x86 результат становится 13.
--------------------
Пишите в личку.
|
|
|
|
|
May 13 2007, 06:24
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 13 2007, 11:35)  А с отсутствующими - интересует  Да ТОЛЬКО с отсутствующими и интересует. К тем которые предупредили - претензий и спроса нет. Цитата Других встречных вопросов не видел. Пост номер 53. Это не вопросы, на которые я "требую" ответа. Это вопросы, которые я прежде всего задал себе и сам не знаю (не знал на тот момент) на них ответа. Но отсутствия ответа на них не позволяет мне прятать голову в песок и обвинять компиляторы не выдавшие warning в кривости. Цитата Я совершенноуже запутался в версиях компиляторов, на которые Вы ссылались. Странно. 4 компилятора не выдающие warning? но выдающие 14 были перечислены рядышком в одной cтроке. Цитата Кстати, если определить i как volatile - в gcc для x86 результат становится 13. Хороший эксперимент! Кроме того, когда я экспериментировал с GNU, я по ленности запихнул эти строчки в готовый поюсовый проект  . Теперь повторив c сишным компилятором удалось получить warning. GCC x86 покинул ряды защитников "14":). С плюсовыи GNU странности, ну да бог с ним - уже не до этого. Нашел время спытать и Borland - он покидает арену с позором - выдает произвольные значения и никаких warning. Microsoft-а у меня не стоит и лично не пытал. Посему на даный момент остается единственный достоверный стойкий оловянный солдатик - OpenWatcom. Всегда (в том числе и с volatile) выдающий 14. Что уже явно может быть исключительно личным мнением разработчиков одного компилятора.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 13 2007, 09:15
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 13 2007, 11:19)  Проблемы с volatile. Чтение volatile переменной может обладать побочными эффектами, неизвестными компилятору, как и запись. Ну с этим все очень просто. Берем Help к компилятору и читаем, что нам обещано: Код An object may be declared with the keyword volatile. Such an object may be freely modified by the program, and its value also may be modified through actions outside the program. Про побочные эффекты, при чтениии это не забота volatile. Характеристика обьекта с модификатором volatile описана четко. Все остальное фантазии и пустые надежды на решение всех проблем одним махом. Цитата Поэтому компилятор не может по своей воле оптимизировать чтение volatile переменных. Может, с осторожностью: Код The keyword volatile indicates to the compiler that care must be taken when optimizing code referring to the object, so that the meaning of the program is not altered. An object that the compiler might otherwise have been able to keep in a register for an extended period of time will be forced to reside in normal storage so that an external change to it will be reflected in the program's behavior. Если вдруг существуют компиляторы налагающие более суровые ограниченя, не сочтите за труд назвать их. Очень полезно для общего развития.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 13 2007, 09:27
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 13 2007, 13:15)  Может, с осторожностью: ... Компилятор - GCC. Не сочтите за труд, прочтите, в конце концов, стандарт языка, или хотя-бы нормальный учебник по языку программирования. Главное назначение volatile - работа с аппаратными регистрами. Например, получение данных из аппаратного FIFO. Изменение количества чтений из такой ячейки памяти приведет к некорректной работе программы. Поэтому атрибут volatile налагает очень жесткие ограничения на любой компилятор: каждое чтение volatile объекта является внешним эффектом программы, поэтому никакая оптимизация не имеет права изменить количество таких чтений. Даже удивительно, что мне приходится Вам излагать настолько базовые понятия. P.S. Убедитесь, пожалуйста, что Watcom поддерживает ANSI C, а не остановился в своем развитии на K&R C.
--------------------
Пишите в личку.
|
|
|
|
|
May 13 2007, 09:38
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 13 2007, 12:27)  Не сочтите за труд, прочтите, в конце концов, стандарт языка Может я чего пропустил? Тогда пожалуйста сюда ссылочку из стандарта про главню задачу volatile: Цитата Главное назначение volatile - работа с аппаратными регистрами. Например, получение данных из аппаратного FIFO Цитата Даже удивительно, что мне приходится Вам излагать настолько базовые понятия. Удивительно другое, что Вы полагаете, что для решения описанных проблем достаточно volatile  Цитата P.S. Убедитесь, пожалуйста, что Watcom поддерживает ANSI C, а не остановился в своем развитии на K&R C. OpenWatcom поддерживает С99. А что в K&R упоминается volatile? Цитата Поэтому атрибут volatile налагает очень жесткие ограничения на любой компилятор Накладываемые ограничения: Цитата The standards encourage compilers to refrain from optimizations concerning accesses to volatile objects that it might perform on non-volatile objects. The C standard leaves it implementation defined as to what constitutes a volatile access. The C++ standard omits to specify this, except to say that C++ should behave in a similar manner to C with respect to volatiles, where possible. The minimum either standard specifies is that at a sequence point all previous accesses to volatile objects have stabilized and no subsequent accesses have occurred. Thus an implementation is free to reorder and combine volatile accesses which occur between sequence points, but cannot do so for accesses across a sequence point. The use of volatiles does not allow you to violate the restriction on updating objects multiple times within a sequence point.
Сообщение отредактировал zltigo - May 13 2007, 09:50
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 13 2007, 09:55
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 13 2007, 13:38)  Может я чего пропустил? Тогда пожалуйста сюда ссылочку из стандарта про главню задачу volatile: Удивительно другое, что Вы полагаете, что для решения описанных проблем достаточно volatile  "Главная задача volatile" описана, безусловно, не в стандарте, а в учебниках по языку. Признаюсь, учебники по языку С я не читал с начала 90-х - но уже в то время все было подробно описано. В стандарте же написано следующее: Цитата An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Therefore any expression referring to such an object shall be evaluated strictly according to the rules of the abstract machine, as described in 5.1.2.3. volatile решает часть задачи работы с аппаратурой, которая касается компилятора. Остальное (например, настройка кеша) касается самой аппаратуры, а не компилятора. Нечего мне приписывать то, что я не писал. P.S. Есть еще такой документ - "Rationale for International Standard—Programming Languages—C" Цитата volatile No cacheing through this lvalue: each operation in the abstract semantics must be performed (that is, no cacheing assumptions may be made, since the location is not guaranteed to contain any previous value). In the absence of this qualifier, the contents of the designated location may be assumed to be unchanged except for possible aliasing. Цитата A static volatile object is an appropriate model for a memory-mapped I/O register. Implementors of C translators should take into account relevant hardware details on the target systems when implementing accesses to volatile objects. For instance, the hardware logic of a system may require that a two-byte memory-mapped register not be accessed with byte operations; and a compiler for such a system would have to assure that no such instructions were generated, even if the source code only accesses one byte of the register. Whether read-modify-write instructions can be used on such device registers must also be considered. Whatever decisions are adopted on such issues must be documented, as volatile access is implementation-defined. A volatile object is also an appropriate model for a variable shared among multiple processes.
--------------------
Пишите в личку.
|
|
|
|
|
May 13 2007, 10:12
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 13 2007, 12:55)  В стандарте же написано следующее: Отлично. К первоисточникам припали  . Ну теперь будучи вооруженным, попробуйте обьяснить, в чем это компилятор провинился: Цитата А вот это явный глюк компилятор. Посмотрите в ассемблере - cколько он раз считывает значение переменной i. Ну и Ваши слова: Цитата каждое чтение volatile объекта является внешним эффектом программы, поэтому никакая оптимизация не имеет права изменить количество таких чтений. Цитата Нечего мне приписывать то, что я не писал. Да??? Были перечислены проблемы ображения к "железу" и сказано про volatile. При этом никакие другие средства не упоминались а в реальной жизни для решения этих проблем использования только volatile (без, например, разбиения на sequence points )недостаточно. Так-что как тогда надо было понимать? P.S. Да, и с "удивлением", пожалуйста поокуратнее.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 13 2007, 10:26
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 13 2007, 14:12)  Отлично. К первоисточникам припали  . Ну теперь будучи вооруженным, попробуйте обьяснить, в чем это компилятор провинился: Да? Уж больно "удивление" выказано было  Да я Вам с самого начала постоянно кидал ссылки на первоисточники - а в ответ получал лишь "жираф большой - ему видней." Провинился Watcom тем, что абстрактная C машина считывает volatile объект два раза - а код, порождаемый компилятором, содержит одно чтение из объекта. Такая оптимизация нарушает требование стандарта, которое я процитировал в предыдущем посте. Кстати. Вы дописали в конце цитату утверждения, что компилятор имеет право комбинировать volatile обращения между соседними sequence point. Так вот, это явный бред. Вы не привели ссылку на источник цитаты - гугл в качестве источника дает документацию на GCC. Это утверждение - явная самодеятельсность авторов GCC. Потому что она противоречит приведенной ранее мною цитате из стандарта. Переупорядочивание обращений к этому не относится. А вот комбинирование может привести к тому, что побочные эффекты от обращения будут потеряны, вместо того, чтобы быть завершены к следующей sequence point.
--------------------
Пишите в личку.
|
|
|
|
|
May 13 2007, 10:37
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Oldring @ May 13 2007, 13:26)  Провинился Watcom тем, что абстрактная C машина считывает volatile объект два раза - а код, порождаемый компилятором, содержит одно чтение из объекта. Такая оптимизация нарушает требование стандарта, которое я процитировал в предыдущем посте. Цитата ..компилятор имеет право комбинировать volatile обращения между соседними sequence point. Так вот, это явный бред. Это утверждение - явная самодеятельсность авторов GCC. Потому что она противоречит приведенной ранее мною цитате из стандарта. Ну как-бы я все понял и осознал - существует только одно правильное толкование "стандарта" и оно принадлежит Oldring. Aвторы компиляторов дружно "отдыхают", ну а остальные фоне этого вообще никто и звать их никак.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 13 2007, 11:03
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(zltigo @ May 13 2007, 14:37)  Aвторы компиляторов дружно "отдыхают", ну а остальные фоне этого вообще никто и звать их никак. Я и говорю: "жираф большой - ему видней". Ладно. Продолжать мне скушно. Адью.
--------------------
Пишите в личку.
|
|
|
|
|
May 13 2007, 12:03
|
Участник

Группа: Новичок
Сообщений: 70
Регистрация: 27-03-07
Пользователь №: 26 533

|
Цитата(zltigo @ May 13 2007, 14:37)  Ну как-бы я все понял и осознал - существует только одно правильное толкование "стандарта" и оно принадлежит Oldring. Aвторы компиляторов дружно "отдыхают", ну а остальные фоне этого вообще никто и звать их никак. Вообще то известно, что авторы компиляторво делают ошибки в полный рост. Для этого достаточно почитать этот форум. Ну а то что в этом случае i не надо читать два раза очень удивительно слышать от человека, который занимается разработкой для микропроцессоров. Тут таких случаев навалом. То что это не так в ваткоме говорит о том, что этот компилятор практически не используется для написания совты связанного с работой с железом и такие ошибки не ВЫЛЕЗЛИ у пользователей.
|
|
|
|
|
May 13 2007, 13:15
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(vromanov @ May 13 2007, 15:03)  Вообще то известно, что авторы компиляторво делают ошибки в полный рост. Удивительно другое, что volatile-"правильный" компилятор пока найти не удалось  . Цитата Ну а то что в этом случае i не надо читать два раза очень удивительно слышать от человека, который занимается разработкой для микропроцессоров. Человек, "который занимается" умеет четко выражать свои мысли посредством vоlatile и разбиения инструкций на sequence point. При этом меня абсолютно устраивает минимально-необходимо-достаточная трактовка volatile присутствующая во всех известных мне компиляторах и процитированная ранее по Watcom-овскому хелпу и документации к GCC. При этом такая трактовка volatile не отметает оптимизацию на корню. Цитата То что это не так в ваткоме говорит о том, что этот компилятор практически не используется для написания совты связанного с работой с железом и такие ошибки не ВЫЛЕЗЛИ у пользователей. Ну то, что я использую под 186 и не только, и то, что IBM-PC это тоже железо - забудем? Но что делать с GCC там ведь вообще "явный бред": Код The standards encourage compilers to refrain from optimizations concerning accesses to volatile objects that it might perform on non-volatile objects. The C standard leaves it implementation defined as to what constitutes a volatile access. The C++ standard omits to specify this, except to say that C++ should behave in a similar manner to C with respect to volatiles, where possible. The minimum either standard specifies is that at a sequence point all previous accesses to volatile objects have stabilized and no subsequent accesses have occurred. Thus an implementation is free to reorder and combine volatile accesses which occur between sequence points, but cannot do so for accesses across a sequence point. The use of volatiles does not allow you to violate the restriction on updating objects multiple times within a sequence point. Так вот, я с этим "бредом" полностью согласен. Нормальная, сбалансированная реализация. Не вырубающая оптимизацию полностью при обращении к Random Access (RAM в том числе) обьектам. "Проблемы" c, например, FIFO должны решаться явным образом разбиением обращений на sequence point. Обращение к FIFO (кстати, как там дела c существованием FIFO в "абстрактной С машине" поминаемй с стандарте дела обстоят? ) не должно висеть тяжким грузом на всем остальном.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 13 2007, 14:08
|

http://uschema.com
   
Группа: Свой
Сообщений: 708
Регистрация: 16-02-06
Из: UK(Ukrainian_Kingdom) Kharkov
Пользователь №: 14 394

|
Цитата(Oldring @ May 11 2007, 22:59)  Почему 14? IMHO правильное значение может быть 12, 13, но никак не 14.  аналогично! почему 14 ??? 13 и баста... вариант с 12 - доспустим,но это добжен быть невероятно глупый компилятор, причем с патароченными критериями и правилами оптимизации... но а 14 откуда берется? и почему у gcc тоже 14??? я прошу, нет, ... требую... объясните плз... я конечно не виликий гуру - но тут то заблудиться трудно! 13 и ничего иного... x = ++i+ ++i разбиваем как это делает компилятор temp1 = ++i (стало 6) temp2 = ++i (стало 7) x=temp1+temp2 (стало 13) от куда 14??? ...и вообще! что это у людей за безгранично глупая привычка все писать без скобок !? что за мода надеяться на безграничный интелект компилятора? ...истинну глаголю - индусы писали это эйфелеву конструкцию! не иначе ...или [CENSORED]! а глупость то видать явно в компиляторах и это напоминает подвох с x=2+2*2, чему равен x? .
Сообщение отредактировал PrSt - May 13 2007, 16:54
--------------------
|
|
|
|
|
May 14 2007, 00:04
|

Знающий
   
Группа: Свой
Сообщений: 723
Регистрация: 29-08-05
Из: Березовский
Пользователь №: 8 065

|
Цитата ... разбиваем как это делает компилятор temp1 = ++i (стало 6) temp2 = ++i (стало 7) x=temp1+temp2 (стало 13)
от куда 14??? ... 1. Да простит меня великий All, что я поднял эту волну... Просто мною овладело любопытство. 2. Я про явное отличие компиляторов С/С++ и С# скажу. Точнее скажу свои доводы, как эти компиляторы понимают код x = ++i + ++i; Компиляторы С/С++ складывают (последняя операция -- сложение) переменную i c переменной i, в то время как C# складывае результат выражения ++i с результатом выражения ++i. Таким образом, для С/С++ на момент сложения переменных, они будут равны 7 (даром, что это одна и та же переменная!), результат получаем -- 14. C# складывает результаты выражений: первый результат на момент сложения равен 6, второй -- 7, что в итоге дает 13. Отсюда вопрос -- что должны складывать компиляторы: результаты выражений или значения переменных? Меня интересует, как так получилось, что возникла такая вольность интерпретации этого злого выражения у компиляторов. Вольность -- это потенциальная опасность переноса кода с одного компайлера на другой. Вот что меня беспокоит. И еще, наверно стоит зайти на РСДН, посмотреть что там говорят гуру. (Сылку я приводил в первом посте.)
Сообщение отредактировал zhevak - May 14 2007, 00:13
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
May 14 2007, 00:07
|
Участник

Группа: Новичок
Сообщений: 70
Регистрация: 27-03-07
Пользователь №: 26 533

|
А то, что значение переменной может поменяться в результате прерывания? Или в начале каждой sequence point прерывание запрещать, а потом разрешать?
Сообщение отредактировал vromanov - May 14 2007, 00:11
|
|
|
|
|
May 14 2007, 00:19
|

Знающий
   
Группа: Свой
Сообщений: 723
Регистрация: 29-08-05
Из: Березовский
Пользователь №: 8 065

|
Цитата(vromanov @ May 14 2007, 06:07)  А то, что значение переменной может поменяться в результате прерывания? Или в начале каждой sequence point прерывание запрещать, а потом разрешать? не-е, ну... предполагается, что переменная i -- это обычная переменная, не volatile. Определена внутри какой-нибудь функции, т.е. размещается либо на стеке, либо в регистрах МП. Иначе говоря, никто из вне ее торкнуть не может.
--------------------
Хочешь рассмешить Бога -- расскажи ему о своих планах!
|
|
|
|
|
May 14 2007, 00:22
|
Участник

Группа: Новичок
Сообщений: 70
Регистрация: 27-03-07
Пользователь №: 26 533

|
Цитата(zhevak @ May 14 2007, 04:19)  не-е, ну... предполагается, что переменная i -- это обычная переменная, не volatile. Про исходный пример все ясно. Так просто нельзя писать, т.к. результат по стандарту не определен. Мы уже про другое.
|
|
|
|
|
May 15 2007, 06:19
|

Частый гость
 
Группа: Свой
Сообщений: 135
Регистрация: 6-04-07
Из: Бронницы
Пользователь №: 26 809

|
Цитата(singlskv @ May 13 2007, 02:53)  Я Вам не помешаю ?  Выскажу свое ИМХО: - Компилятор который не выдет warning в такой ситуации, вне зависимости от уровня оптимизации, это компилятор который не следует стандарту С. - соглашусь с Oldring, 12 или 13 еще как-то укладывается в то, как учитывая стандарт С, компилятор должен был бы разбирать это выражение - результат 14 для большинства компиляторов говорит только о том, что "очень хотелось соптимизировать" и компилятор "успешно" справился с этой задачей... 2 zligoЕсли Вы имеете в виду такую предсказуемость работы "оптимизаторов" в компиляторах, то с Вами я тоже полностью согласен  все операции детерминированы . в выражении ++i + ++i во втором "отделении спектакля" производиться только сложение двух подвыражений - а подвыражения эти - равны текущему значению i (вариант а), либо вычисленному значению подвыражения (вариант б). нигде не написано в стандарте про то какой вариант является правильным - именно поэтому это и называется undefined behavior. неправ тот компилятор который не показал ворнинг - а число при этом можно выдавать где то от 12-ти до 14-ти
--------------------
если еррата пуста - это не хорошо а плохо
|
|
|
|
|
May 15 2007, 06:26
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(cebotor @ May 15 2007, 10:19)  все операции детерминированы . в выражении ++i + ++i во втором "отделении спектакля" производиться только сложение двух подвыражений - а подвыражения эти - равны текущему значению i (вариант а), либо вычисленному значению подвыражения (вариант б). нигде не написано в стандарте про то какой вариант является правильным - именно поэтому это и называется undefined behavior. неправ тот компилятор который не показал ворнинг - а число при этом можно выдавать где то от 12-ти до 14-ти  Еще раз. Результат всего выражения компилятор имеет право выдать любой - хоть -666, потому что undefined behavior. Но интерпретация значения выражения ++i прописана в стандарте совершенно четко. Результат не является lvalue. Следовательно, это не есть значение переменной i, а именно вычисленное значение подвыражения. В корректных выражениях различие можно обнаружить только если i - volatile.
--------------------
Пишите в личку.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|