|
Детская ошибка |
|
|
|
May 2 2016, 06:22
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Недавно столкнулся с одной странностью (по крайней мере для меня). Хотелось бы понять. Есть фрагмент года (упрощенный до безобразия): CODE int16u temp1, temp2; for (int32u i = 0; i < 10; i++) { temp1 = 0x0001; temp2 = 0xFFFE; if (~temp1 != temp2) continue; temp2 = temp1; }
Так вот, в этом фрагменте условный оператор и код после него никогда не выполняется. В отладчике после выполнения операции "temp2 = 0xFFFE;" происходит сразу переход на начало цикла. Переменные объявлены как int16u (== unsigned short (16 бит беззнаковое)) При этом никаких предупреждений на этапе компиляции. Если переменные объявить как int32u (== unsigned long (32 бита беззнаковое)), то условный оператор выполняется, но естественно результат всегда true. И код работает как надо только в таком варианте: CODE int16u temp1, temp2; for (int32u i = 0; i < 10; i++) { temp1 = 0x0001; temp2 = 0xFFFE; temp1 = ~temp1; if (temp1 != temp2) continue; temp2 = temp1; }
В этом случае выполняются все операторы, входящие в тело цикла. IAR C/C++ Compiler for ARM 7.40.3.8902 (7.40.3.8902) Добавлю: Оптимизация отключена. Проект под микроконтроллер STM32F105VCT6
Сообщение отредактировал amiller - May 2 2016, 06:41
|
|
|
|
|
May 2 2016, 07:08
|
Частый гость
 
Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364

|
А если так: Код int16u temp1, temp2; for (int32u i = 0; i < 10; i++) { temp1 = 0x0001; temp2 = 0xFFFE; if ( (int16u)(~temp1) != temp2 ) continue; temp2 = temp1; }
|
|
|
|
|
May 2 2016, 07:16
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(AleksBak @ May 2 2016, 10:08)  А если так: Код int16u temp1, temp2; for (int32u i = 0; i < 10; i++) { temp1 = 0x0001; temp2 = 0xFFFE; if ( (int16u)(~temp1) != temp2 ) continue; temp2 = temp1; } Так как Вы предлагаете, тоже работает. Хотя в этом меня тоже смущает один момент. После выполнения оператора "~" не должна меняться размерность переменной. Но больше всего меня беспокоит результат компиляции первого моего примера. В ассемблерном коде вообще отсутствует условный оператор и всё, что после него. И при этом никаких предупреждений от компилятора. Как это можно рассматривать? Бага компилятора? Или есть более простое объяснение?
|
|
|
|
|
May 2 2016, 07:24
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (amiller @ May 2 2016, 10:16)  После выполнения оператора "~" не должна меняться размерность переменной. Может меняться и после и до. В данном случае меняется до. Читайте про неявные приведения типов (implicit type conversion) и правила расширения целых (integer promotion rules). QUOTE (amiller @ May 2 2016, 10:16)  Как это можно рассматривать? Бага компилятора? Или есть более простое объяснение? Как обычно (в 99.99% случев) - компилятор не виноват, просто программист не удосужился изучить язык, который пытается использовать.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 2 2016, 07:36
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(Сергей Борщ @ May 2 2016, 10:24)  Может меняться и после и до. В данном случае меняется до. Читайте про неявные приведения типов (implicit type conversion) и правила расширения целых (integer promotion rules). Как обычно - компилятор не виноват, просто программист не удосужился изучить язык, который пытается использовать. Про неявное приведение типов соглашусь. Ну а судя по второй фразе, Вы точно знаете причину по которой компилятор удаляет часть кода, и при этом нет ни одного предупреждения? Так сообщите пожалуйста. Мне это по прежнему непонятно. Речь идёт о самом первом примере. Поясняю ещё раз. Дело не в том, что результат выполнения условной операции неверный. Дело в том, что условный оператор не выполняется вообще. В исходной программе после этого условного оператора у меня было под сотню строк кода до окончания цикла. И весь этот код отсутствует в ассемблере. CODE \ 00000000 0xB538 PUSH {R3-R5,LR} 68 int16u temp1, temp2; 69 70 for (int32u i = 0; i < 10; i++) \ 00000002 0x2000 MOVS R0,#+0 \ ??main_0: (+1) \ 00000004 0x280A CMP R0,#+10 \ 00000006 0xD206 BCS.N ??main_1 71 { 72 temp1 = 0x0001; \ 00000008 0x2101 MOVS R1,#+1 \ 0000000A 0x000C MOVS R4,R1 73 temp2 = 0xFFFE; \ 0000000C 0xF64F 0x71FE MOVW R1,#+65534 \ 00000010 0x000D MOVS R5,R1 74 if (~temp1 != temp2) continue; 75 temp2 = temp1; 76 } \ 00000012 0x1C40 ADDS R0,R0,#+1 \ 00000014 0xE7F6 B.N ??main_0 77 78 79 80
Сообщение отредактировал amiller - May 2 2016, 07:44
|
|
|
|
|
May 2 2016, 08:09
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (amiller @ May 2 2016, 10:36)  Ну а судя по второй фразе, Вы точно знаете причину по которой компилятор удаляет часть кода, и при этом нет ни одного предупреждения? Так сообщите пожалуйста. Мне это по прежнему непонятно. Речь идёт о самом первом примере. Да, знаю. После выполнения расширения типов ваше условие выполняется всегда, для любых значений переменных temp1 и temp2 (0xFFFFxxxx всегда не равно 0x0000xxxx). Поэтому условие всегда истинно и проверять его не имеет смысла - вы же хотите, чтобы ваша программа была маленькой и быстрой, поэтому компилятор просто выкинул бессмысленную проверку и весь код, который никогда, ни при каких условиях выполняться не будет.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
May 2 2016, 08:21
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(Сергей Борщ @ May 2 2016, 11:09)  Да, знаю. После выполнения расширения типов ваше условие выполняется всегда, для любых значений переменных temp1 и temp2 (0xFFFFxxxx всегда не равно 0x0000xxxx). Поэтому условие всегда истинно и проверять его не имеет смысла - вы же хотите, чтобы ваша программа была маленькой и быстрой, поэтому компилятор просто выкинул бессмысленную проверку и весь код, который никогда, ни при каких условиях выполняться не будет. Позволю себе усомниться по двум пунктам: 1. Раньше во всех случаях, когда в коде был фрагмент, который никогда не выполняется, я получал от компилятора соответствующее предупреждение. В данном случае - нет. 2. Я уже писал, что если переменные объявить как int32u, то условие тоже всегда истинно. Но в этом случае компилятор не выбрасывает из кода условный оператор и всё что после него. Есть вероятность, что ответ на этот простой вопрос, как обычно, лежит в более сложных материях. Кстати уровень оптимизации = Null, поэтому с этой стороны не следует ожидать от компилятора излишней предупредительности.
|
|
|
|
|
May 2 2016, 11:30
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(amiller @ May 2 2016, 10:16)  Но больше всего меня беспокоит результат компиляции первого моего примера. В ассемблерном коде вообще отсутствует условный оператор и всё, что после него. Вы будете смеяться, но компилятор вовсе не обязан на каждый чих в исходнике генерить код. Обычно на минимальном уровне оптимизации генерит, но тоже не всегда и не везде. Компилятор отвечает только за то, что сгенерированный код выдаст тот результат, который следует из исходника. Если исходник никакого результата не подразумевает, то компилятор может не генерировать ничего - и будет в своём праве. Цитата(amiller @ May 2 2016, 11:21)  1. Раньше во всех случаях, когда в коде был фрагмент, который никогда не выполняется, я получал от компилятора соответствующее предупреждение. В данном случае - нет. Это вам показалось. Если припомните, какое именно было предупреждение, то поймёте, что в данном случае оно не применимо. А если не припомните, то это просто испорченный телефон. Короче, показалось. Цитата(amiller @ May 2 2016, 11:21)  Но в этом случае компилятор не выбрасывает из кода условный оператор и всё что после него. Есть вероятность, что ответ на этот простой вопрос, как обычно, лежит в более сложных материях. Не надо там искать сложных материй. В одном случае выкинул бессмысленный код, в другом - нет. Подумаешь - бывает сплошь и рядом. Компилятор - это просто программа, а не какое-то высшее существо с высшим разумом.
|
|
|
|
|
May 2 2016, 11:35
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(scifi @ May 2 2016, 14:26)  Вы будете смеяться, но компилятор вовсе не обязан на каждый чих в исходнике генерить код. Обычно на минимальном уровне оптимизации генерит, но тоже не всегда и не везде. Компилятор отвечает только за то, что сгенерированный код выдаст тот результат, который следует из исходника. Если исходник никакого результата не подразумевает, то компилятор может не генерировать ничего - и будет в своём праве. В этом с Вами я согласен, но предупредить то надо. Например если поставить внутри функции безусловный return, генерится предупреждение. А в данном случае всё происходит молча. Ну и не совсем понятен алгоритм. В одном случае молча выбрасывает код, а в другом очень похожем случае всё же генерит код, который тем не менее также не выполняется. Например, если в том же примере заменить строку с условным оператором "if (true) continue;" то получаем предупреждение: Warning[Pe111]: statement is unreachable - что логично. А в моем примере это происходило "молча". Тем не менее всем спасибо! Ошибка локализована. И с утверждением, что компилятор "не обязан", я согласен. Остальное в общем то уже нюансы функционирования программы, которой также является и компилятор.
Сообщение отредактировал amiller - May 2 2016, 11:44
|
|
|
|
|
May 2 2016, 12:20
|
Частый гость
 
Группа: Участник
Сообщений: 132
Регистрация: 6-02-16
Из: г. Баку
Пользователь №: 90 364

|
Цитата(amiller @ May 2 2016, 15:35)  В этом с Вами я согласен, но предупредить то надо. Например если поставить внутри функции безусловный return, генерится предупреждение. А в данном случае всё происходит молча. Ну и не совсем понятен алгоритм. В одном случае молча выбрасывает код, а в другом очень похожем случае всё же генерит код, который тем не менее также не выполняется. ... Я было подумал, что IAR-овский компилер тут и поэтому может так, а оказывается и gcc аналогично себя ведет в этой ситуации. Цитата(amiller @ May 2 2016, 15:35)  ... И с утверждением, что компилятор "не обязан", я согласен... Почему? Ведь мог и написать что-то. Но нет промолчал как рыба.
|
|
|
|
|
May 2 2016, 13:49
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(amiller @ May 2 2016, 15:35)  В этом с Вами я согласен, но предупредить то надо. Зря соглашаетесь. Хороший компилятор (и некий стандарт предупреждений) должен уметь определять опечатки и вероятные ошибки. Согласие в данном случае с тем, что он не обязан. Обнаружил как-то у себя код Код { bla bla bla; bla bla bla; } while (++i<10); В котором в первой строке перед скобкой пропущен do. Просматривая такой код, ошибка не особо и видна. А компилятору заметить здесь что-то неладное совсем не сложно. Абыдно. ---- Но "стандарт предупреждений" неудачное название. История показывает, что каждый (американский) стандартер желает наВрать, где сидит фазан. Лучше "правила" с приоритетами. Опечатку выделил. Опечатался буквой си.
Сообщение отредактировал GetSmart - May 2 2016, 14:10
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
May 2 2016, 16:19
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(GetSmart @ May 2 2016, 16:49)  Обнаружил как-то у себя код Код { bla bla bla; bla bla bla; } while (++i<10); В котором в первой строке перед скобкой пропущен do. Просматривая такой код, ошибка не особо и видна. А компилятору заметить здесь что-то неладное совсем не сложно. Абыдно. Ой ли? Код { bla bla bla; bla bla bla; } while (++i<10);
|
|
|
|
|
May 3 2016, 15:33
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(GetSmart @ May 2 2016, 19:49)  Код { bla bla bla; bla bla bla; } while (++i<10); В котором в первой строке перед скобкой пропущен do. Просматривая такой код, ошибка не особо и видна. А компилятору заметить здесь что-то неладное совсем не сложно. Абыдно. И что в этом коде неладно??? Следуя Вашей логике, компилятор на выражение: int x; тоже должен выдавать варнинг, ведь может Вы там хотели написать: unsigned int x; Компилятор не должен думать за программиста.
|
|
|
|
|
May 3 2016, 16:23
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(jcxz @ May 3 2016, 19:33)  И что в этом коде неладно??? Это должен был быть цикл на 10 итераций с выпрыгиванием из него при определённых обстоятельствах. А получилась только одна итерация. Искренне считаю, что обнаруживать такую СТРАННУЮ последовательность должен компилятор. Правило: если идёт свободный блок, за которым while без тела, то выдать варнинг. Иначе на while без тела с неволатильными переменными в условии выдавать ремарку. Тело в данном случае - ключевой признак этих правил. Цитата(Baser @ May 2 2016, 20:18)  Пример вы выбрали для подтверждения своей мысли сильно неудачный. Именно такие странности хотелось бы чтобы компилятор "подчёркивал" при компиляции, как Ворд подчёркивает текст при просмотре. Пример тот самый. Как и у ТС.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
May 3 2016, 19:47
|

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

|
QUOTE (GetSmart @ May 3 2016, 19:23)  Искренне считаю, что обнаруживать такую СТРАННУЮ последовательность должен компилятор. Правило: если идёт свободный блок, за которым while без тела, то выдать варнинг. Блок может использоваться по причинам совершенно не связанным с ошибкой - локализация объявления переменной, макроподстановка... Так что не надо стенаний, особенно, если стеной стоите, как мне помится, на "нормальности" while(константа){}
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 3 2016, 21:42
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(zltigo @ May 3 2016, 23:47)  Так что не надо стенаний, особенно, если стеной стоите, как мне помится, на "нормальности" while(константа){}  while / if (const) ==> ремарка. Продолжаю считать, как и ранее. Полезные конструкции. С тремя уровнями сообщений компилятора. То бишь с двумя не препятствующими генерации прошивки. В идеале на pred_while(1) и post_while(0) даже ремарку не выдавать. Если макроса в скобках не было. Цитата(zltigo @ May 3 2016, 23:47)  Блок может использоваться по причинам совершенно не связанным с ошибкой - локализация объявления переменной, макроподстановка... Макроподстановку легко обнаружить и учесть. Логика на порядки проще оптимизации кода.
Сообщение отредактировал GetSmart - May 3 2016, 21:36
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
May 6 2016, 04:58
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(amiller @ May 2 2016, 14:35)  Ошибка локализована. И с утверждением, что компилятор "не обязан", я согласен. Остальное в общем то уже нюансы функционирования программы, которой также является и компилятор. 1. Странно, что локализована. Лично мне резануло глаз присваивание константы в цикле, при том что константа объявлена не volatile. Стало быть, весь цикл вообще теряет смысл. И никакие неявные приведения типов тут вообще ни причем. 2. Упрощения, это хорошо. Но приводить упрощенный Си-код вне функции, дело бесполезное. Хотя бы потому, что не понятно, переменные temp1 и temp2 локальные или глобальные. 3. Насчет обязан или не обязан компилер. Конечно не обязан, его дело компилировать. Зато статический анализатор кода сразу завопил бы, с негодованием. Благо в последних IAR встроен C-Stat. Настоятельно рекомендую натравить его на код. Гарантирую(с), он еще много "чудес" выявит в коде.
|
|
|
|
|
May 6 2016, 06:23
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(Tahoe @ May 6 2016, 07:58)  1. Странно, что локализована. Лично мне резануло глаз присваивание константы в цикле, при том что константа объявлена не volatile. Стало быть, весь цикл вообще теряет смысл. И никакие неявные приведения типов тут вообще ни причем. 2. Упрощения, это хорошо. Но приводить упрощенный Си-код вне функции, дело бесполезное. Хотя бы потому, что не понятно, переменные temp1 и temp2 локальные или глобальные. Если ошибка воспроизводится в такой простой конструкции, то зачем присылать страницы кода? Переменные temp1 и temp2 локальные, объявление на строчку выше. В исходном коде переменным присваиваются не константы, а результат, возвращаемый функцией. А после условного оператора ещё сотня строк в цикле. Меня лично смутило, что компилятор без предупреждений выбросил из программы большой фрагмент кода. Это было главное, на что я обратил внимание. Но раз общественность не забилась в праведном гневе, значит все считают это нормальным. А тогда вопрос и не стоит обсуждать. Тем более в коде был грешок с приведением типов, на который мне правильно указали.
|
|
|
|
|
May 6 2016, 08:32
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(amiller @ May 6 2016, 09:23)  Если ошибка воспроизводится в такой простой конструкции, то зачем присылать страницы кода? Еще раз. Нет никакой конструкции. Тот огрызок, что приведен, не позволяет нормально определить источник проблемы. Цитата(amiller @ May 6 2016, 09:23)  Переменные temp1 и temp2 локальные, объявление на строчку выше. В исходном коде переменным присваиваются не константы, а результат, возвращаемый функцией. "Не в преферанс, а в лотерею. Не миллион, а пять тыщ. И не выиграл, а проиграл." (с) Я только не понял, это вот "в исходном коде не константы", это просто поприкалываться захотелось или на полном серьезе? Цитата(amiller @ May 6 2016, 09:23)  Но раз общественность не забилась в праведном гневе, значит все считают это нормальным. А тогда вопрос и не стоит обсуждать.Тем более в коде был грешок с приведением типов, на который мне правильно указали. А, общественность... Все считают... Тогда другое дело. Это заявка на успех. Желаю удачи.
|
|
|
|
|
May 6 2016, 08:58
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(Tahoe @ May 6 2016, 11:32)  Еще раз. Нет никакой конструкции. Тот огрызок, что приведен, не позволяет нормально определить источник проблемы.
"Не в преферанс, а в лотерею. Не миллион, а пять тыщ. И не выиграл, а проиграл." (с)
Я только не понял, это вот "в исходном коде не константы", это просто поприкалываться захотелось или на полном серьезе?
А, общественность... Все считают... Тогда другое дело. Это заявка на успех. Желаю удачи. Извините, но я не понял к чему это всё, что Вы написали. Или Вы считаете, что если я скопирую сюда полный код функции, Вы точно укажете на источник проблемы? Или Вы считаете, что я школьник, и то, что я прислал к делу не имеет отношения, а ошибка в другом месте? Смею Вас заверить, что это не так. И проблема воспроизводится именно в том "огрызке", который я разместил, я специально проверял. Для этого больше ничего не нужно, достаточно этот фрагмент разместить в пустом main(). Ну разве что скорректировать названия типов. И в отзывах была информация, что это характерно не только для компилятора IAR. В gcc тоже проблема воспроизводится.
|
|
|
|
|
May 6 2016, 14:19
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(zltigo @ May 6 2016, 16:44)  Опять  . Да не проблема это компилятора, ЛЮБОЙ компилятор ОБЯЗАН поступить аналогично. Это АБСОЛЮТНО Ваша проблема связанная с незнаним языка. Я нигде не писал, что претендую на звание "гуру". Более того, на ошибках учусь с удовольствием, как на своих, так и на чужих. Но никто не дал на мой вопрос чёткий ответ. 1. Если переменные int16u, то компилятор код выбрасывает. У меня нет вопросов к самому факту этого события. У меня вопрос к тому, почему это происходит без предупреждения (молча). Я не считаю, что это нормальное поведение компилятора. 2. Однако если переменные int32u, то с точки зрения выполнения кода ничего не меняется. Но тем не менее в этом случае, код компилируется (не выбрасывается). Хотя результат также предопределен и известен заранее. Я уже вроде успокоился по этому поводу, но находятся всё новые люди, которые утверждают, что я не знаю язык, но не дают чёткого ответа, почему компилятор поступает именно так. Может Вы попробуете?
|
|
|
|
|
May 6 2016, 15:29
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(amiller @ May 6 2016, 17:19)  1. Если переменные int16u, то компилятор код выбрасывает. У меня нет вопросов к самому факту этого события. У меня вопрос к тому, почему это происходит без предупреждения (молча). Предупреждения придуманы для удобства. Они помогают отловить ошибки в коде. Нет никаких стандартов, регламентирующих поведение компилятора в этом вопросе. Более того, авторы компилятора тоже никаких обязательств здесь на себя не берут. Следовательно, вопрос "почему" довольно бесперспективный. Если вас так уж гложет, вам надо добыть исходники этого компилятора и разобраться, что там происходит. Или спросить того, кто делает этот компилятор. В этом форуме, понятное дело, вы таких не найдёте. Цитата(amiller @ May 6 2016, 17:19)  2. Однако если переменные int32u, то с точки зрения выполнения кода ничего не меняется. Но тем не менее в этом случае, код компилируется (не выбрасывается). Хотя результат также предопределен и известен заранее. Я уже вроде успокоился по этому поводу, но находятся всё новые люди, которые утверждают, что я не знаю язык, но не дают чёткого ответа, почему компилятор поступает именно так. Здесь применим тот же ответ, что я дал выше. "Нет никаких стандартов, регламентирующих поведение компилятора в этом вопросе" и далее по тексту. В общем, не те вопросы задаёте, не о том думаете. Кстати, именно вот эти неправильные вопросы и дают людям повод усомниться в вашем знании языка Си.
|
|
|
|
|
May 6 2016, 16:31
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(amiller @ May 6 2016, 17:19)  1. Если переменные int16u, то компилятор код выбрасывает. Последний раз, больше даже пытаться не стану. Если десять раз присвоить константу temp1=0x1, хоть что-то изменится, хоть на одном проходе из 10? Если не изменится, то бишь даже без всякой оптимизации, temp1 и temp2 _всегда_ будут иметь одно и то же значение. Результат if (~0x0001!= 0xFFFE) будет отличаться хоть на одном из проходов? И плевать какие там типы, все 10 раз будет одно и то же. А строчка temp2 = temp1; будет вообще игнорироваться. В итоге, имеем несколько строчек бессмысленного кода, который вырождается в пару присваиваний. И никакого цикла здесь нет. Другой вопрос, когда вместо констант будет присваиваться результат функции. В этом случае, может и дойдет до кривых типов. Но в приведенном куске, с константами, до этого дело даже не доходит.
|
|
|
|
|
May 7 2016, 02:52
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(Tahoe @ May 6 2016, 19:31)  Последний раз, больше даже пытаться не стану. Если десять раз присвоить константу temp1=0x1, хоть что-то изменится, хоть на одном проходе из 10? Если не изменится, то бишь даже без всякой оптимизации, temp1 и temp2 _всегда_ будут иметь одно и то же значение. Результат if (~0x0001!= 0xFFFE) будет отличаться хоть на одном из проходов? И плевать какие там типы, все 10 раз будет одно и то же. А строчка temp2 = temp1; будет вообще игнорироваться.
В итоге, имеем несколько строчек бессмысленного кода, который вырождается в пару присваиваний. И никакого цикла здесь нет. Другой вопрос, когда вместо констант будет присваиваться результат функции. В этом случае, может и дойдет до кривых типов. Но в приведенном куске, с константами, до этого дело даже не доходит. Уважаемый, не рассказывайте мне пожалуйста, о бессмысленных присвоениях и сравнениях констант. Вы невнимательно читали предыдущую переписку. Представленный фрагмент кода имеет только один смысл - продемонстрировать наличие проблемы в действиях компилятора. Вместо того, чтобы доказывать, что автор сообщения не умеет писать программы, постарались бы понять, что он хотел донести своим сообщением. Цитата(Сергей Борщ @ May 7 2016, 00:37)  Меняется. При приведении int16_t -> int32_t происходит расширение знака. Уточнение: мои типы int16u и int32u соответствуют uint16_t u uint32_t. Не уверен, что в этом случае можно говорить о расширении знака. Когда я говорил "ничего не меняется", я имел в виду, что условие в условном операторе по прежнему всегда true (не зависит от типа переменных), но в одном случае код компилируется, а в другом выбрасывается.
|
|
|
|
|
May 7 2016, 05:14
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(amiller @ May 7 2016, 05:52)  Представленный фрагмент кода имеет только один смысл - продемонстрировать наличие проблемы в действиях компилятора. Представленный фрагмент ничего не демонстрирует, от слова "вообще". Особенно, проблем с компилером. Единственное, что он демонстрирует, это лень и, как следствие, дурную манеру изложения, в стиле "Рабинович напел".
|
|
|
|
|
May 7 2016, 05:37
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(Tahoe @ May 7 2016, 08:14)  Представленный фрагмент ничего не демонстрирует, от слова "вообще". Особенно, проблем с компилером. Единственное, что он демонстрирует, это лень и, как следствие, дурную манеру изложения, в стиле "Рабинович напел". А кроме голословных утверждений Вам есть что сообщить? В чём именно заключается лень или дурные манеры? Чтобы убедиться в том, а чём я пишу, достаточно: 1. Вставить в программу фрагмент кода (соответствующим образом изменив названия типов). 2. Откомпилировать. Убедиться, что начиная с условного оператора в листинге код не формируется, а предупреждений не выдается. 3. Поменять типы на int32u (или uint32_t, как удобно). 4. Снова откомпилировать,убедиться, что в листинге код есть, хотя результат условного оператора также предопределен, как и в первом случае. 5. Задуматься, возможно сделать выводы. 6. Если понятна причина такого поведения компилятора, рассказать автору вопроса. 7. Если причина неизвестна, то лучше промолчать, а не опускаться до стиля "сам дурак".
|
|
|
|
|
May 7 2016, 07:59
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(amiller @ May 7 2016, 08:37)  2. .....Убедиться, что начиная с условного оператора в листинге код не формируется, а предупреждений не выдается. Стандарт С++. 5.3.1 Unary operators. 8 The operand of the unary - operator ..... Integral promotion is performed on integral or enumeration operands. ..... The type of the result is the type of the promoted operand. Т.е. стандарт предписывает все целочисленные типы, а это харе-образные, с "int" и enum, расширять до знакового int и так далее в зависимости от размера. Тип результата - расширенный операнд. В случае с int16u результатом операции будет "signed int". Также как и ,например, результат операции (char) + (char) -> signed int; Но вопрос Вы подняли правильно. Очень надеюсь, что найдутся разработчики компилятора, которые проигнорируют маразматические моменты исторически сложившегося стандарта.
Сообщение отредактировал aiwa - May 7 2016, 08:00
|
|
|
|
|
May 7 2016, 09:24
|

Местный
  
Группа: Свой
Сообщений: 231
Регистрация: 19-12-08
Из: Новосибирск
Пользователь №: 42 594

|
Цитата(amiller @ May 7 2016, 11:37)  ... 5. Задуматься, возможно сделать выводы. ... Предлагаю один: не полагаться на компилятор /что он все приведения типов и приоритеты операций соблюдёт/ Расставляйте скобки и явные касты. (это не я придумал: жизнь учит) Одноразовое изделие - одно, о нём и темы нет. Как только нужна переносимость кода весь геморрой - ваш. Если соломку не стелить регулярно. Темы о глюках компиляторов, стандартах и их (не)соблюдении вечны как и холивар.
|
|
|
|
|
May 7 2016, 10:25
|

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

|
QUOTE (svss @ May 7 2016, 12:24)  не полагаться на компилятор /что он все приведения типов и приоритеты операций соблюдёт/ Вообще то он СОБЛЮДЕТ! Лет 25 уже основные компиляторы сколь-нибудь явных ошибок НЕ допускают. QUOTE Расставляйте скобки и явные касты. (это не я придумал: жизнь учит) А вот это скоерее, да. Только НЕ для компилятора, а для себя, ибо в отличие от компилятора человку сложнее держать в голове те же 15 уровней приоритета. Но и маниакально распихивать скобки и приведения типов тоже не дело.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 7 2016, 13:47
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(amiller @ May 7 2016, 08:37)  А кроме голословных утверждений Вам есть что сообщить? ... 2. Откомпилировать. Убедиться, что начиная с условного оператора в листинге код не формируется, а предупреждений не выдается. Я все сообщил еще в своем первом ответе. И почему код отсутствует, и что запустить, что бы увидеть желаемое предупреждение. Код, приведенный в первом посте - бессмысленный. С какой стати компилер должен предупреждать об этом? Это широко распространенный прием, например при условной компиляции, когда часть кода намеренно превращается бессмысленное. С какой стати компилеру лезть не в свое дело? Откуда он знает, это программер бестолково пишет, как в данном случае или код заточен под 100500 вариантов? А вот статический анализатор, тот не просто предупредит, вопить будет. Однако отсутствие вопросов и комментариев по статическому анализатору, говорит о том, что даже не понятно, о чем вообще речь. Так может, чем продолжать дерзить, запустить хоть раз C-STAT или хотя бы выяснить, что это такое?
|
|
|
|
|
May 7 2016, 14:04
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(Tahoe @ May 7 2016, 16:47)  Так может, чем продолжать дерзить, запустить хоть раз C-STAT или хотя бы выяснить, что это такое? Ну извините пожалуйста. Я сразу не обратил внимание, что Вы из Москвы. Простите молодого пятидесятилетнего провинциала, что я вообще вступил с Вами в дискуссию. Мне надо было посыпать голову пеплом и с восторгом внимать Вам. Только напомните мне пожалуйста, что именно Вы сказали по существу конкретного вопроса, который я задал?
|
|
|
|
|
May 7 2016, 16:06
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(amiller @ May 7 2016, 17:04)  сразу не обратил внимание, что Вы из Москвы. Простите молодого пятидесятилетнего провинциала Не понял, как это относится к запуску C-STAT, зато стало ясно, что имею дело с очередным не признанным гением. В этом месте позвольте откланяться. Удачи.
|
|
|
|
|
May 7 2016, 17:33
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(Tahoe @ May 7 2016, 19:06)  Не понял, как это относится к запуску C-STAT, зато стало ясно, что имею дело с очередным не признанным гением. В этом месте позвольте откланяться. Удачи. Как же Вы любите ярлыки навешивать... Вообще то мои слова появились в ответ на Ваше "продолжать дерзить". По моему Вы вообще не поняли, о чём идёт речь. 1. Я не прошу помощи в написании кода или в оценке его качества. 2. Не нужно советов по использованию дополнительного ПО, так как это совсем не относится к делу. 3. И речь не шла о правильности или эффективности примера, его (примера) задача - продемонстрировать описанную проблему. В своем сообщении я описал проблему в работе компилятора, которую увидел. И хотел выяснить нормальное это поведение или нет и почему компилятор ведёт себя по разному в похожих случаях. А конкретная задача в написании программы была решена ещё до того, как было написано сообщение. Ведь не все вопросы обязаны быть на тему "помогите, не работает...".
|
|
|
|
|
May 7 2016, 20:41
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(Огурцов @ May 7 2016, 19:57)  а не проще ли было писать компилятор так, что во всех случаях выдавать предупреждение, а не когда как Та тут как бы компилятор и не виноват, он всего лишь следует предписаниям стандарта. Даже дело не в в отсутствии предупреждения, в нарушении законов булевой алгебры. Но желание преемственности побеждает здравый смысл.
|
|
|
|
|
May 7 2016, 22:31
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(Огурцов @ May 8 2016, 00:59)  вы можете между собой договориться, есть в предписании стандарта речь про предупреждения или нет ? А о чем должно быть предупреждение? В сухом остатке получается переменная булевого типа, равная нулю. А само нарушение закона двойного отрицания происходит в процессе обработки выражения. Причем, в старых 16-битных компиляторах обработка происходит корректно.
|
|
|
|
|
May 8 2016, 06:18
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Огурцов @ May 8 2016, 12:05)  о своих действиях - выбросил код, обнаружил невыполняемый или недостижимый код - сообщи Код 1: x = y + 2 + 3; Выбросил 2+3, заменил на 5. Сообщать? Код 2: int x, y, z; x = y + 2; z = (y + 2) * 3; Выбросил (y+2) во втором выражении, заменив на x*3. Сообщать? Код 3: #define DEF_X некое const-выражение int x; if (DEF_X == 1 && x == 1) { выражение1; } else { выражение2; }; если DEF_X != 1, то будет выкинута операция if и выражение1. Сообщать? ...и т.п.
|
|
|
|
|
May 8 2016, 06:53
|
Гуру
     
Группа: Участник
Сообщений: 3 928
Регистрация: 28-03-07
Из: РФ
Пользователь №: 26 588

|
> Выбросил 2+3, заменил на 5. Сообщать? скорее нет, чем да >Выбросил (y+2) во втором выражении, заменив на x*3. Сообщать? скорее да, чем нет >если DEF_X != 1, то будет выкинута операция if и выражение1. Сообщать? определённо да, ибо иначе использовался ifdef Цитата(jcxz @ May 8 2016, 06:32)  если среди них трудно найти полезные пишите так, чтобы не было неполезных
|
|
|
|
|
May 8 2016, 07:18
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(jcxz @ May 8 2016, 09:32)  IAR всё может. Только какая польза от такого кол-ва предупреждений, если среди них трудно найти полезные и всё равно их приходится отключать? Отчего же сразу отключать? "Сначала - так, потом - вот так" (с) Сначала компилируем, чтобы без ошибок, потом блох начинаем вычесывать. Потом чисто будет, можно и не проверять. Да, Назначения (Target) можно разные создать, чтоб одной кнопкой мышки... У меня два обычно, Debug и Release. Можно добавить Checked, типа...
|
|
|
|
|
May 8 2016, 09:07
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(ViKo @ May 8 2016, 08:55)  Прочитав тему еще раз, понял, что топикстартер привел гипотетический пример, который и не пробовал компилировать. И народ кинулся обсуждать, приводить доводы за и против для того, что в реальности невозможно. Предлагаю выдать проверенный компилятором исходный текст. Ну что же Вы право... Если усомнились, что же сами не проверили? example1.c - переменные 16 битные, код не формируется (example1.lst). example2.c - переменные 32 битные, код формируется (example2.lst). Оптимизация - None. Понятно, что в данном конкретном случае, когда присваиваются константы, компилятор на высоком уровне оптимизации может выбросить вообще весь код. Но без оптимизации на этом фрагменте всё воспроизводится так, как я описал.
example.zip ( 2.66 килобайт )
Кол-во скачиваний: 23
|
|
|
|
|
May 8 2016, 10:35
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Keil Example1 CODE ; generated by Component: ARM Compiler 5.06 update 1 (build 61) Tool: ArmCC [4d35ad] ; commandline ArmCC [--c99 --list --split_sections --debug -c --asm --interleave -o.\objects\example1.o --asm_dir=.\Listings\ --list_dir=.\Listings\ --depend=.\objects\example1.d --cpu=Cortex-M3 --apcs=interwork -O0 --diag_suppress=9931 -I"D:\ViKo\Works\Keil works\(Keil) Example\RTE" -I"D:\ViKo\Works\Keil works\(Keil) Example\RTE\Device\STM32F103VC" -IC:\Design\Keil\ARM\PACK\ARM\CMSIS\4.5.0\CMSIS\Include -IC:\Design\Keil\ARM\PACK\Keil\STM32F1xx_DFP\2.1.0\Device\Include -D__UVISION_VERSION=518 -D_RTE_ -DSTM32F10X_HD --omf_browse=.\objects\example1.crf Source\example1.c] THUMB
AREA ||i.main||, CODE, READONLY, ALIGN=1
main PROC ;;;1 int main () 000000 2000 MOVS r0,#0 ;;;2 { ;;;3 unsigned short temp1, temp2; ;;;4 for (unsigned int i = 0; i < 10; i++) 000002 e009 B |L1.24| |L1.4| ;;;5 { ;;;6 temp1 = 0x0001; 000004 2101 MOVS r1,#1 ;;;7 temp2 = 0xFFFE; 000006 f64f72fe MOV r2,#0xfffe ;;;8 if (~temp1 != temp2) continue; 00000a 43cb MVNS r3,r1 00000c 4293 CMP r3,r2 00000e d000 BEQ |L1.18| 000010 e001 B |L1.22| |L1.18| ;;;9 temp2 = temp1; 000012 460a MOV r2,r1 000014 bf00 NOP ;8 |L1.22| 000016 1c40 ADDS r0,r0,#1 ;4 |L1.24| 000018 280a CMP r0,#0xa ;4 00001a d3f3 BCC |L1.4| ;;;10 } ;;;11 } 00001c 2000 MOVS r0,#0 00001e 4770 BX lr ENDP
__ARM_use_no_argv EQU 0
Example2 CODE ; generated by Component: ARM Compiler 5.06 update 1 (build 61) Tool: ArmCC [4d35ad] ; commandline ArmCC [--c99 --list --split_sections --debug -c --asm --interleave -o.\objects\example2.o --asm_dir=.\Listings\ --list_dir=.\Listings\ --depend=.\objects\example2.d --cpu=Cortex-M3 --apcs=interwork -O0 --diag_suppress=9931 -I"D:\ViKo\Works\Keil works\(Keil) Example\RTE" -I"D:\ViKo\Works\Keil works\(Keil) Example\RTE\Device\STM32F103VC" -IC:\Design\Keil\ARM\PACK\ARM\CMSIS\4.5.0\CMSIS\Include -IC:\Design\Keil\ARM\PACK\Keil\STM32F1xx_DFP\2.1.0\Device\Include -D__UVISION_VERSION=518 -D_RTE_ -DSTM32F10X_HD --omf_browse=.\objects\example2.crf Source\example2.c] THUMB
AREA ||i.main||, CODE, READONLY, ALIGN=1
main PROC ;;;1 int main () 000000 2000 MOVS r0,#0 ;;;2 { ;;;3 unsigned int temp1, temp2; ;;;4 for (unsigned int i = 0; i < 10; i++) 000002 e009 B |L1.24| |L1.4| ;;;5 { ;;;6 temp1 = 0x0001; 000004 2101 MOVS r1,#1 ;;;7 temp2 = 0xFFFE; 000006 f64f72fe MOV r2,#0xfffe ;;;8 if (~temp1 != temp2) continue; 00000a 43cb MVNS r3,r1 00000c 4293 CMP r3,r2 00000e d000 BEQ |L1.18| 000010 e001 B |L1.22| |L1.18| ;;;9 temp2 = temp1; 000012 460a MOV r2,r1 000014 bf00 NOP ;8 |L1.22| 000016 1c40 ADDS r0,r0,#1 ;4 |L1.24| 000018 280a CMP r0,#0xa ;4 00001a d3f3 BCC |L1.4| ;;;10 } ;;;11 } 00001c 2000 MOVS r0,#0 00001e 4770 BX lr ENDP
__ARM_use_no_argv EQU 0
Keil победил!
|
|
|
|
|
May 8 2016, 12:13
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(Огурцов @ May 8 2016, 09:05)  о своих действиях - выбросил код, обнаружил невыполняемый или недостижимый код - сообщи Так он выбросил код, проанализировав if(0). Случай исключительно вырожденный, так что и сообщать ему не о чем. Грубо говоря, процесс "ошибки" заложен внутри выражения (~temp1 != temp2) в результате перехода lvalue temp1 16 -> rvalue temp1 32.
|
|
|
|
|
May 8 2016, 12:24
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(aiwa @ May 8 2016, 15:13)  Так он выбросил код, проанализировав if(0). Случай исключительно вырожденный, так что и сообщать ему не о чем.
Грубо говоря, процесс "ошибки" заложен внутри выражения (~temp1 != temp2) в результате перехода lvalue temp1 16 -> rvalue temp1 32. А давайте утрируем ситуацию: CODE main () { unsigned int temp1, temp2; for (unsigned int i = 0; i < 10; i++) { temp1 = 0x0001; temp2 = 0xFFFE; if (1) continue; temp2 = temp1; } }
Вроде как здесь всё ещё более определено. Так ведь нет. В этом случае видим предупреждение: Warning[Pe111]: statement is unreachable H:\work\test\example2.c 9 Где логика то?
|
|
|
|
|
May 8 2016, 12:29
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(zltigo @ May 8 2016, 06:44)  Маразм процветает  . Причем тут "старые", или "новые" - в огороде бузина а в Киеве дядька  . Компиляция такого "примера" зависит от разрядности int целевой платформы и ни от чего более. Спасибо, конечно, за оценку но речь, как бы не о механизме действия компилятора, - их вполне полно и лаконично уже описал Сергей Борщ. Приведу аналогию: чтобы обойти лишнюю писанину при желании char сделать беззнаковым, компиляторы добавили галочку "считать 'char' как unsigned. В нашем случае требуется добавление лишней писанины для предписания явного преобразования. Галочки не хватает.
|
|
|
|
|
May 8 2016, 12:54
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(amiller @ May 8 2016, 15:24)  Вроде как здесь всё ещё более определено. Так ведь нет. В этом случае видим предупреждение: Warning[Pe111]: statement is unreachable H:\work\test\example2.c 9 Где логика то? Точно не знаю, могу лишь предположить, что в этом случае все уже предопределено на уровне синтаксического разбора, поэтому компилятор выдает предупреждение. Но если Вы поменяете на Код int16u tst = 1; if(tst) continue; то сообщение уже может отсутствовать. Цитата(ViKo @ May 8 2016, 15:34)  И во что же должно продвинуться беззнаковое uint16_t 0xfffe? Разве не в 0x0000fffe, независимо, знаковое или без 32 битовое? И продвигаться надо когда? Когда результат логического сравнения используется? Сказано же, сравнивать 16-битовые беззнаковые. По-моему, IAR накосячил. Продвинутое uint16_t 0xfffe равно 0xfffffffe и оно является строго знаковым, независимо от знаковости или беззнаковости исходной переменной. Процесс продвижки начинается с упоминания имени переменной в выражении, а именно temp1 в выражении означает значение rvalue (signed int 32), полученное из lvalue переменной temp1 с помощью правил расширения.
|
|
|
|
|
May 8 2016, 13:30
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Огурцов @ May 8 2016, 12:53)  >Выбросил (y+2) во втором выражении, заменив на x*3. Сообщать? скорее да, чем нет Зачем??? Это обычная оптимизация никак не влияющая на выполнение кода. Таких оптимизаций в исходниках может быть тысячи случаев. Какая от них польза? Один только вред из-за того, что среди такого мусора пропадут полезные сообщения. Цитата(Огурцов @ May 8 2016, 12:53)  >если DEF_X != 1, то будет выкинута операция if и выражение1. Сообщать? определённо да, ибо иначе использовался ifdef  Каким боком тут ifdef??? Его значение всегда будет true. А смысл этого кода например в том, что есть некий общий модуль исходного кода на 2 разных устройства. В одном устройстве например установлено два чипа SPI-FLASH в другом - один. И данный define задаёт кол-во чипов. Это если Вы не поняли. Цитата(ViKo @ May 8 2016, 13:18)  Отчего же сразу отключать? "Сначала - так, потом - вот так" (с) Сначала компилируем, чтобы без ошибок, потом блох начинаем вычесывать. Потом чисто будет, можно и не проверять. Причём тут ошибки? Ошибок нет. Преобразование типа - это стандартная операция. Тем более - оптимизация и лишний код удаляемый оптимизацией. Таких событий будут тысячи мест в коде. Цитата(aiwa @ May 8 2016, 18:54)  Продвинутое uint16_t 0xfffe равно 0xfffffffe и оно является строго знаковым, независимо от знаковости или беззнаковости исходной переменной. Хмммм.... А что такое "продвинутое uint16_t"? Я отстал от жизни и в си ввели новые "продвинутые" типы? И как именно из беззнакового 0xFFFE получается 0xFFFFFFFE?
|
|
|
|
|
May 8 2016, 14:27
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(jcxz @ May 8 2016, 16:30)  Хмммм.... А что такое "продвинутое uint16_t"? Я отстал от жизни и в си ввели новые "продвинутые" типы? И как именно из беззнакового 0xFFFE получается 0xFFFFFFFE? Продвинутый - это буквальный перевод термина "promotions", наверное неудачный. Правила "integral promotions" предписывают расширение до типа способного полностью представить исходное значение в порядке int, unsigned int, long int, unsigned long int, и т.д. Первый тип для 32-го компилятора - знаковый int может полностью представить весь диапазон значений uint16_t, поэтому и происходит расширение uint16_t - > signed int (32).
|
|
|
|
|
May 8 2016, 14:43
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(ViKo @ May 8 2016, 17:37)  Правильно, продвигается до знакового целого. Но почему 65534 должно "превратиться в -1? jcxz, об чем вы, о каких ошибках? Я где хочу,там пишу с ошибками, а компилятор их ловит. Где хочу читаю все ремарки. Ах, точно, Вы правы - у меня опечятка: в результате расширения получается знаковый 0x0000FFFE.
|
|
|
|
|
May 8 2016, 15:04
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(ViKo @ May 8 2016, 17:45)  О! Может, топикстартер все же напутал с определением своего типа беззнакового? Когда я разместил примеры в файлах - там уже стандартные названия сишных типов, как раз чтобы не было путаницы.
|
|
|
|
|
May 8 2016, 15:24
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(ViKo @ May 8 2016, 17:45)  О! Может, топикстартер все же напутал с определением своего типа беззнакового? Знаковость тут присутствует лишь в силу упоминания правил "integral promotions". В случае, если бы temp1 и temp2 были знаковыми, результат был совершенно тем же. Грубо говоря, написанный код if (~temp1 != temp2) компилятор видит как if(~rvalue32(temp1)!=rvalue32(temp2)) ~rvalue32(temp1) совершенно другое значение нежели ~temp1.
Сообщение отредактировал aiwa - May 8 2016, 15:40
|
|
|
|
|
May 8 2016, 15:53
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(ViKo @ May 8 2016, 18:40)  Почему никто не комментирует листинги от Кейла? Все пытаются оправдать ИАР. Кто такой Билл наслышан, Кейла не знаю? ИАР действует в соответствии со стандартом, а этот результат заложен там. И это не оправдание, а всего лишь констатация печального факта. Цитата(ViKo @ May 8 2016, 18:45)  И Кейл их скомпилировал, как надо. С АРМами пока не работал, но если не ошибаюсь, то Вы компилировали для 16-ти битного режима. А в нем же uint16_t совпадает с unsigned int, поэтому происходит расширение до rvalue16(temp1). При этом ~rvalue16(temp1) полностью совпадает с ~temp1.
Сообщение отредактировал aiwa - May 8 2016, 15:54
|
|
|
|
|
May 8 2016, 16:20
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(ViKo @ May 8 2016, 18:57)  Кейл, он же Кайл, он же Keil (нем.), он же куплен ARM (АРМ), поскольку, как выясняется, компилирует без косяков. aiwa, ошибаетесь. Я ничего не утверждаю - увидел в Ваших листингах "THUMB" вот и высказал предположение. Если он компилирует верно и для 32-разрядного режима, то только можно этому порадоваться. Есть надежда, что и в стандарт внесут соответствующие изменения.
|
|
|
|
|
May 8 2016, 16:41
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ViKo @ May 8 2016, 20:37)  Правильно, продвигается до знакового целого. Но почему 65534 должно "превратиться в -1? jcxz, об чем вы, о каких ошибках? Я где хочу,там пишу с ошибками, а компилятор их ловит. Где хочу читаю все ремарки. Я не знаю о каких ошибках писали Вы. Не узнаёте свои слова? Уже начали отмечать или ещё не закончили?  Цитата(Огурцов @ May 8 2016, 20:53)  таким, что если бы я хотел написать нечто осмысленное, то использовал ifdef а так как написан if, то вероятно тут косяк, о коем компилятор обязан сообщить Ещё раз прочитайте по буквам: причём там ifdef??? Для справки: ifdef - используется для проверки определено ли данное имя или нет. В моём примере константа всегда определена. Но может принимать разные значения (1, 2, ...). И то, что там написан if - вполне нормально, а никакой не косяк. Поэтому компилятор правильно и молчит. В си аргумент оператора if - выражение, которое может состоять из переменных и констант. На этапе выполнения значение этого выражения вычисляется. На этапе компиляции может осуществляться оптимизация этого выражения. Варнингов на приведённые мною примеры не должно быть никаких. Что и подтверждает IAR. PS: Тут уже все отмечают что-ль???  Цитата(ViKo @ May 8 2016, 21:45)  Почему никто не комментирует листинги от Кейла? Все пытаются оправдать ИАР. Может потому что его никто не пользует?  И зачем оправдывать IAR? Он не выдал варнинг? Так и правильно сделал!
|
|
|
|
|
May 8 2016, 16:43
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(ViKo @ May 8 2016, 18:57)  Кейл, он же Кайл, он же Keil (нем.), он же куплен ARM (АРМ), поскольку, как выясняется, компилирует без косяков. Да? Именно поэтому сразу после покупки АРМ заменил кейловский убогий компилятор своим (он же RealView)? Кейл неплохо делает всё остальное (среда, отладчик, поддержка огромного зоопарка МК), но в компиляторах они точно не чемпионы.
|
|
|
|
|
May 8 2016, 17:00
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(ViKo @ May 8 2016, 21:57)  Кейл, он же Кайл, он же Keil (нем.), он же куплен ARM (АРМ), поскольку, как выясняется, компилирует без косяков. aiwa, ошибаетесь. Посмотрел Ваш результат компиляции Кейл. Результат этот не делает чести Кейлу - теперь точно не променяю IAR на него! IAR на этапе компиляции правильно оптимизировал выражение выкинув ненужный код. Кейл-же оставил бессмысленный код. Значение выражения всегда будет "истина". Так что: MVNS и CMP - лишние, а BEQ надо заменить на безусловный B. Цитата(aiwa @ May 8 2016, 21:53)  С АРМами пока не работал, но если не ошибаюсь, то Вы компилировали для 16-ти битного режима. А в нем же uint16_t совпадает с unsigned int, поэтому происходит расширение до rvalue16(temp1). При этом ~rvalue16(temp1) полностью совпадает с ~temp1. Бред. В ARM разрядность операций и регистров не зависит от режима - хоть Thumb хоть ARM - всё равно 32 бита. Режимы ARM и Thumb - определяют только способ кодирования инструкций и их количество. К тому-же, указанный ТС-ом МК, имеет ядро Cortex-M, которое знает только набор инструкций Thumb2. Учите матчасть!
|
|
|
|
|
May 8 2016, 18:11
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Дополню для ясности. У Cortex-M команды - THUMB2 - смесь 16-битовых и 32пбитовых команд. А регистры, естественно, 32-битовые. jcxz, я не отмечаю... Но подлечиться не помешает. Перестаю понимать людей. Что касается Кейла, то он сделал то, что ему задали. Задам ему оптимизацию, посмотрим, что выдаст... Кто чемпион... чем сердце успокоится... scifi, значит, RealView чемпион. Мне одинаково хорошо. Задал -o3. Но, поскольку temp не volatile, Кейл выкинул всё. В обоих случаях снова все одинаково. CODE ; generated by Component: ARM Compiler 5.06 update 1 (build 61) Tool: ArmCC [4d35ad] ; commandline ArmCC [--c99 --list --split_sections --debug -c --asm --interleave -o.\objects\example1.o --asm_dir=.\Listings\ --list_dir=.\Listings\ --depend=.\objects\example1.d --cpu=Cortex-M3 --apcs=interwork -O3 --diag_suppress=9931 -I"D:\ViKo\Works\Keil works\(Keil) Example\RTE" -I"D:\ViKo\Works\Keil works\(Keil) Example\RTE\Device\STM32F103VC" -IC:\Design\Keil\ARM\PACK\ARM\CMSIS\4.5.0\CMSIS\Include -IC:\Design\Keil\ARM\PACK\Keil\STM32F1xx_DFP\2.1.0\Device\Include -D__UVISION_VERSION=518 -D_RTE_ -DSTM32F10X_HD --omf_browse=.\objects\example1.crf Source\example1.c] THUMB
AREA ||i.main||, CODE, READONLY, ALIGN=1
main PROC ;;;311 /* end of stdint.h */ ;;;3 int main () 000000 2000 MOVS r0,#0 |L1.2| ;;;4 { ;;;5 uint16_t temp1, temp2; ;;;6 for (unsigned int i = 0; i < 10; i++) 000002 1c40 ADDS r0,r0,#1 000004 280a CMP r0,#0xa ;;;7 { ;;;8 temp1 = 0x0001; ;;;9 temp2 = 0xFFFE; ;;;10 if (~temp1 != temp2) continue; 000006 d3fc BCC |L1.2| ;;;11 temp2 = temp1; ;;;12 } ;;;13 } 000008 2000 MOVS r0,#0 00000a 4770 BX lr ENDP
__ARM_use_no_argv EQU 0
|
|
|
|
|
May 8 2016, 22:52
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(ViKo @ May 8 2016, 22:42)  Таки да, операция ~temp1 дает число 0xFFFFFFFE. Вот если результат инверсии сохранить в uint16_t, тогда урежется до 0xFFFE. Вот именно. Для правильной генерации кода, наверное, предлагается напомнить компилятору о правильной размерности таким кодом: if( (int16u)(~temp1) != temp2) Который явно не способствует читабельности. Абыдно, что у С++ масло маслянное.
Сообщение отредактировал aiwa - May 8 2016, 22:53
|
|
|
|
|
May 9 2016, 06:43
|

Профессионал
    
Группа: Свой
Сообщений: 1 003
Регистрация: 20-01-05
Пользователь №: 2 072

|
Цитата(amiller @ May 6 2016, 09:23)  Если ошибка воспроизводится в такой простой конструкции, то зачем присылать страницы кода? Переменные temp1 и temp2 локальные, объявление на строчку выше. В исходном коде переменным присваиваются не константы, а результат, возвращаемый функцией. А после условного оператора ещё сотня строк в цикле. Где-то вы не договариваете. Тот код, что вы привели с локальными переменными, с позиции современных компиляторов является "мертвым" кодом и может быть выкинут безо всяких предупреждений даже на низших уровнях оптимизации. Перепишем ваш пример в более корректную форму: Код unsigned short test1(unsigned short temp1, unsigned short temp2) { for (unsigned i = 0; i < 10; i++) { if (~temp1 != temp2) continue; temp2 = temp1; } return temp2; } и посмотрим на труд комиплятора (gcc -O2): Код movl %esi, %eax ret Все просто превосходно - не правда ли? Цикл заменен единственной инструкцией, а все потому, что сам код при любых значениях входных переменных будет всегда возвращать значение переменной temp2. Компилятор увидел это, и выкинул абсолютно ненужный цикл. Что-же касается молчаливого выбрасывания "мертвого" кода, то это есть следствие многопроходности современных компиляторов и весьма сложных структур внутреннего представления. Кроме того, конструкции вида Код constexpr bool WTF = true; ... if (WTF) { save_the_world(); } else { destroy_the_moon(); } широко используются при условной компиляции без использования препроцессора.
|
|
|
|
|
May 9 2016, 07:54
|
Частый гость
 
Группа: Участник
Сообщений: 176
Регистрация: 20-02-14
Из: Томск
Пользователь №: 80 612

|
Цитата(halfdoom @ May 9 2016, 09:43)  Где-то вы не договариваете. Тот код, что вы привели с локальными переменными, с позиции современных компиляторов является "мертвым" кодом и может быть выкинут безо всяких предупреждений даже на низших уровнях оптимизации. Поверьте, ничего я не "не договариваю". В топике я разместил код в таком виде, в каком проблема (на мой взгляд)) воспроизводилась, и с которой я столкнулся. Я считал что этого достаточно, так как легко можно проверить. Затем, в сообщении 53 я привел законченные примеры кода и результат компиляции IAR. Вопрос, как и тема раздела в целом, касается исключительно IAR. Причём на уровне оптимизации - None. Причём я по прежнему считаю, что логика формирования предупреждений у IAR страдает. 1. Переменные 16 битные - код выбрасывается без предупреждений. Вроде мы обосновали, что это логично. 2. Переменные 32 битные - код присутствует, хотя он в этом случае он не менее бессмысленный. Хотя здесь может быть такой аргумент: Две 32 битные переменные имеют право сравниваться, а компилятор заранее не обязан предсказывать результат. 3. В случае "if (true) continue;" предупреждение есть, хотя результат ещё более определен, чем в первом случае. Для меня лично (по результатам обсуждения) логично бы выглядело наличие предупреждения и в первом пункте. Но видимо это уже связано с многопроходностью компилятора (код выбрасывается на уровне, когда предупреждения уже не формируются). Наверное нельзя это оценивать однозначно как хорошо или как плохо. Просто надо иметь в виду, что такая ситуация возможна и больше обращать внимание на такие неявные на первый взгляд особенности языка и действий компилятора.
|
|
|
|
|
May 9 2016, 11:10
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(halfdoom @ May 9 2016, 09:43)  Перепишем ваш пример в более корректную форму: Код // глобальные переменные #define A ((int16u)0x01)
int16u temp1 = A; int16u temp2 = ~A; ............................ void func(void) { if (~temp1 != temp2) { printf(" не выполняется закон двойного отрицания ~~A = A"); } } В результате работы компилятора будет выполнен выводящий сообщение блок.
Сообщение отредактировал aiwa - May 9 2016, 11:12
|
|
|
|
|
May 9 2016, 12:41
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(zltigo @ May 9 2016, 14:56)  Если "программист" не знает языка и НЕ ХОЧЕТ читать сообщения компилятора ПОДАВИВ ИХ, то да. Вы вопрос качества языка постоянно сводите к вопросу качества программиста.
|
|
|
|
|
May 9 2016, 12:49
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(aiwa @ May 9 2016, 15:41)  Вы вопрос качества языка постоянно сводите к вопросу качества программиста. Язык такой, какой он есть. Де факто стандарт для программирования микроконтроллеров. Мы все крепки задним умом. Было бы неплохо, конечно, обобщить передовой опыт, родить супер-пупер язык для МК, который в 100500 раз более лучше, чем Си, и отправить его на машине времени туда, куда надо. Но что-то мне подсказывает, что троечникам это не поможет. Учебник всё равно надо читать.
|
|
|
|
|
May 9 2016, 13:38
|

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

|
QUOTE (aiwa @ May 9 2016, 15:41)  Вы вопрос качества языка постоянно сводите к вопросу качества программиста. Есть язык, он описан. Как любой ЖИВОЙ язык он имеет опоеделенные правила и умолчания. Их надо знать. Если кто не знает языка и более того, плюет на сообщения, которые генерят компиляторы написанные знающими язык людьми, то это есть проблема "качества порограммиста" и только его. QUOTE (scifi @ May 9 2016, 15:49)  родить супер-пупер язык.. Спасибо, не надо. Уже рожали. Когда пытабтся рожать язык ради языка, а не дела, то получабтся ублюдки типа Ada, Python и иже с ними.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 9 2016, 16:00
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(Tahoe @ May 6 2016, 08:58)  3. Насчет обязан или не обязан компилер. Конечно не обязан, его дело компилировать. Зато статический анализатор кода сразу завопил бы, с негодованием. Благо в последних IAR встроен C-Stat. Настоятельно рекомендую натравить его на код. Гарантирую(с), он еще много "чудес" выявит в коде.  Если в законе что-то не написано прямым текстом, то работает принцип аналогии. Ещё со времён динозавров, компиляторы паскаля, си и многих других языков выдавали сообщение/варнинг при сравнении беззнаковой переменной со знаковой константой или или переменной с константой вне диапазона этой переменной. В примере топикстартера есть аналогичные признаки: сравнение двух выражений, которые заведомо вне диапазона друг друга. Программер имеет право ожидать, что ОБНАРУЖИВ подобную ситуацию, компилятор укажет на неё аналогично константе. Если компилятор не слишком оптимизирующий, то он действительно может не выдавать сообщение, т.к. во время компиляции эту ситуацию не видит. Компилятор, опознавший always-result в выражении с переменными всё-таки должен (ака вектор эволюции) выдавать сообщение, по аналогии с другими предупреждениями. И профсоюз по защите прав программистов должен лоббировать эти правила ))) Молчание ИАРа тянет на недоработку. Если в публичных и непубличных нормативах не было явно указано на данную ситуацию.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
May 9 2016, 16:11
|

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

|
QUOTE (GetSmart @ May 9 2016, 19:00)  Ещё со времён динозавров, компиляторы паскаля, си и многих других языков выдавали сообщение/варнинг при сравнении беззнаковой переменной со знаковой константой или или переменной с константой вне диапазона этой переменной. Они и сейчас так делают. QUOTE Молчание ИАРа тянет на недоработку. Если в публичных и непубличных нормативах не было явно указано на данную ситуацию. Никакого МОЛЧАНИЯ у IAR, как и других нет, если не не подавлять сообщения. IAR в отношении сообщалок о возможном непонимании, пожалуй даже говорливее всех других: temp2 = ~A; [Pa091]: operator operates on value promoted to int (with possibly unexpected result) if( ~temp1 != temp2) [Pa091]: operator operates on value promoted to int (with possibly unexpected result) [Pe068]: integer conversion resulted in a change of sign Так что может хватит здесь пургу нести?
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 9 2016, 16:51
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ May 9 2016, 18:49)  Было бы неплохо, конечно, обобщить передовой опыт, родить супер-пупер язык для МК, который в 100500 раз более лучше, чем Си, и отправить его на машине времени туда, куда надо. Но что-то мне подсказывает, что троечникам это не поможет. Учебник всё равно надо читать. Неумехи просто станут делать другие ошибки. И опять будут во всём винить компилятор. А больше ничего не изменится.
|
|
|
|
|
May 9 2016, 16:57
|

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

|
QUOTE (dxp @ May 9 2016, 19:29)  Питон - великолепный язык, очень простой, но при этом необычайно мощный, гибкий. Ага. Беды начинаются, когда "обучившиеся программированию" начинают на нем программировать  . QUOTE И создавался он не ради языка, а как язык для обучения программированию Вот то, что он создавался для обучения программированию - вот это и есть родимое пятно всех "языков ради языка". Ни Си ни Си++, ни тот же Perl не создавались для обучения, они создавались для РАБОТЫ. QUOTE , но оказался очень эффективным и для решения практических задач. "Мама мыла раму..." ©  . В реальности, все хуже - не далее, как месяц назад очередная утилитка тупо отказалась запускаться вываливаясь с характерными питоновскими воплями  . Утилитка о NXP/Jennic просто командная строка, но зачем то размером 250K и DLL-ок на полмега. За что?
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
May 9 2016, 23:30
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(halfdoom @ May 9 2016, 17:51)  Если сделать первый операнд знаковым, то результат может показаться странным, т.к. числа до 0х8000 будут давать другой результат. Вот как раз если первый операнд сделать знаковым, то в случае операции ~ красота картинки сохранится: temp2 = 0xFFFE расширится его до 0xFFFFFFFE, а последующая операция ~temp2 обнулит лишние старшие навязанные два байта. Поэтому в начальном примере код if(~(signed int16)temp2 !=temp1) continue; даст ожидаемый результат. Цитата(halfdoom @ May 9 2016, 17:51)  И что вас здесь смущает? Согласно великому классику "В компиляторе все должно быть прекрасно...". В нашем конкретном случае с логическими побитовыми операциями вынужденность добавления явных преобразований похожих на Код if(~(signed int16)temp2 !=temp1) continue;
либо
if( (unsigned int16)(~temp2) !=temp1) continue; наводит на мысль, что некоторые моменты в стандарте шиворот-навыворот.
Сообщение отредактировал aiwa - May 9 2016, 23:31
|
|
|
|
|
May 10 2016, 04:20
|

Профессионал
    
Группа: Свой
Сообщений: 1 003
Регистрация: 20-01-05
Пользователь №: 2 072

|
Цитата(aiwa @ May 10 2016, 02:30)  наводит на мысль, что некоторые моменты в стандарте шиворот-навыворот. Стандарт не обязан быть логичным для всех, потому что это стандарт. Однако если вспомнить, что все операции над переменными типа char и short производятся только после приведения к типу int, то многое становится понятным. Почему к int? Потому что существовали и, видимо, существуют архитектуры в которых арифметические операции возможны только для операндов с размером машинного слова, которое и представлено типом int. Иными словами, правила преобразований в С архитектурно зависимы, и в спорных случаях следует использовать явное приведение типов. Кроме того, попробуйте разобраться, как должны работать следующие операторы: Код unsigned short a, b;
if (~(a + b) & ~0xf) {...}
short a, b;
if (~(a + b) & ~0xf) {...}
|
|
|
|
|
May 10 2016, 05:13
|

Местный
  
Группа: Свой
Сообщений: 231
Регистрация: 19-12-08
Из: Новосибирск
Пользователь №: 42 594

|
Цитата(zltigo @ May 9 2016, 17:56)  Если "программист" не знает языка и НЕ ХОЧЕТ читать сообщения компилятора ПОДАВИВ ИХ, то да. Бывает хуже. Например IAR выдаёт предупреждение "unreachable code", а Keil то же место тихо-спокойно пропускает. (прямо относится к исходному мессаджу) О сколько нам открытий трудных..
|
|
|
|
|
May 10 2016, 06:57
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
QUOTE (zltigo @ May 9 2016, 22:57)  Ага. Беды начинаются, когда "обучившиеся программированию" начинают на нем программировать  . Беспредметное, безосновательное утверждение. QUOTE (zltigo @ May 9 2016, 22:57)  Вот то, что он создавался для обучения программированию - вот это и есть родимое пятно всех "языков ради языка". Ни Си ни Си++, ни тот же Perl не создавались для обучения, они создавались для РАБОТЫ. Языком для обучения он позиционировался в 1990 году, с тех пор практически сразу стал языком для решения практических задач. Его ни в коем случае нельзя сравнивать с C/C++ - совершенно разные возможности и ниши, но если сравнивать с перлом, то сравнение будет не в пользу последнего. QUOTE (zltigo @ May 9 2016, 22:57)  "Мама мыла раму..." ©  . В реальности, все хуже - не далее, как месяц назад очередная утилитка тупо отказалась запускаться вываливаясь с характерными питоновскими воплями  . Утилитка о NXP/Jennic просто командная строка, но зачем то размером 250K и DLL-ок на полмега. За что? Понятия не имею, в чём вы. Программа на питоне - это текстовый скрипт. Для исполнения она требует исполняемой среды. Про какие dll речь, мне не ведомо. Если наводите критику, так делайте это предметно. Конкретно что кривого в питоне, какие косяки в его дизайне. Про Аду не спрашиваю, про неё сам знаю. И Ада - действительно искусственно созданный ЯП по ТЗ МО США. Но питон - нет, у него совершенно другая история и свой путь развития. И питону уже не надо доказывать своё право на существование - он давно это доказал делом. Когда я познакомился с питоном лет 10 назад, так забыл как страшный сон эти sed'ы и awk, и с тех пор все утилиты для себя пишу на питоне, ни разу не пришлось разочароваться. И у всех, кого знаю, кто познакомился с питоном, чем плотнее знакомство, тем выше оценка. Подозреваю, что вы с ним реально почти не знакомы, но пришлось столкнуться с парой образчиков говнокода, отсюда и мнение о языке. Тут можно напомнить, что на сях легко наговнкодить так, что питонам и не снилось. Но это не характеризует сам язык.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
May 10 2016, 07:58
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(halfdoom @ May 10 2016, 07:20)  Стандарт не обязан быть логичным для всех, потому что это стандарт. Полностью согласен, но мне кажется он должен при возможности следовать канонам формальной логики. Компилятору желательно еще быть и удобным: повторюсь с примером, когда знаковый тип 'char' компилятор всегда трактует как 'unsigned char' по желанию пользователя. Цитата(halfdoom @ May 10 2016, 07:20)  Потому что существовали и, видимо, существуют архитектуры в которых арифметические операции возможны только для операндов с размером машинного слова, которое и представлено типом int. Иными словами, правила преобразований в С архитектурно зависимы, и в спорных случаях следует использовать явное приведение типов. Да этот вопрос как бы и не касается архитектуры - только небольшая рокировка явного и неявного преобразования типов исключительно для операции ~: операции результат которой остается в разрядной рамке операнда. Если компилятор способен сгенерировать ожидаемый код при явном приведении типов ((uint16_t)~temp1), то неплохо бы иметь такую возможность по умолчанию, не мозоля пальцы на явное преобразование и впоследствии глаза при чтении текста. Для полноты картины при бинарных операциях неплохо бы проводить расширение к большему по размеру операнду. Цитата(halfdoom @ May 10 2016, 07:20)  Кроме того, попробуйте разобраться, как должны работать следующие операторы: Код unsigned short a, b;
if (~(a + b) & ~0xf) {...}
short a, b;
if (~(a + b) & ~0xf) {...} Все довольно просто: результат (unsigned short+unsigned short) не будет 'unsigned short' потому что операция суммирования выходит за пределы разрядной сетки 'unsigned short' и результат будет зависеть от архитектуры в согласии с правилами целочисленного расширения.
Сообщение отредактировал aiwa - May 10 2016, 08:05
|
|
|
|
|
May 10 2016, 08:13
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(aiwa @ May 10 2016, 10:58)  повторюсь с примером, когда знаковый тип 'char' компилятор всегда трактует как 'unsigned char' по желанию пользователя. Тип char можно назвать знаковым только по неведению. Не забивайте себе голову лишними предрассудками, а просто загляните в стандарт. Да, неопределённость в вопросе знаковости типа char раздражает. Видимо, есть "исторические причины". Тем не менее, с типом char не надо делать арифметику. Тип char - он для букв, а не чисел. Цитата(aiwa @ May 10 2016, 10:58)  Если компилятор способен сгенерировать ожидаемый код при явном приведении типов ((uint16_t)~temp1), то неплохо бы иметь такую возможность по умолчанию, не мозоля пальцы на явное преобразование и впоследствии глаза при чтении текста. Код, который для вас кажется ожидаемым, для кого-то другого легко может быть неожиданным. Логика стандарта при приведении типов абсолютно понятна: она заточена под традиционную арифметику с числами. Операции над битами - это нечто иное. Ну что ж, привыкайте. Почитайте стандарт, и тогда компилятор не будет выдавать "неожиданный код".
|
|
|
|
|
May 10 2016, 08:49
|

Профессионал
    
Группа: Свой
Сообщений: 1 003
Регистрация: 20-01-05
Пользователь №: 2 072

|
Цитата(aiwa @ May 10 2016, 10:58)  Все довольно просто: результат (unsigned short+unsigned short) не будет 'unsigned short' потому что операция суммирования выходит за пределы разрядной сетки 'unsigned short' и результат будет зависеть от архитектуры в согласии с правилами целочисленного расширения. Пример немного не об этом, но уж раз вы завели речь о разрядной сетке - при использовании uint8_t вместо short все равно будет расширение типа до int, хотя результат помещается в short. Цитата(dxp @ May 10 2016, 09:57)  Языком для обучения он позиционировался в 1990 году, с тех пор практически сразу стал языком для решения практических задач. Его ни в коем случае нельзя сравнивать с C/C++ - совершенно разные возможности и ниши, но если сравнивать с перлом, то сравнение будет не в пользу последнего. Это, конечно, жуткий оффтопик, но здесь с вами согласен - сравнивать питон следует только с перлом или авк. Цитата(dxp @ May 10 2016, 09:57)  Если наводите критику, так делайте это предметно. Конкретно что кривого в питоне, какие косяки в его дизайне. Претензий к нему не много, но они вшиты намертво и меняться не будут: отвратительный дизайн ООП модели (числа и строки не являются объектами, никуда не годный синтаксис доступа к родительским классам - сравните с C++); очень медленные треды (из-за кривого дизайна интерпретатора), решается вывертами типа мультипроцессинга; global/nonlocal - это вообще без комментариев; де-факто существуют две несовместимые версии языка: python2/python3, а так-же наблюдается антагонизм сторонников как первого, так и второго; однострочные лямбды - ограничение, видимо, произрастает из семантической значимости величины отступа. Мы попытались перенести проект написанный на C++ и убедились, что овчинка совершенно не стоит выделки. А вот для скриптов, тест-модулей и прочих несложных программ питон подходит просто идеально, но здесь с ним в конкуренцию вступает Ruby.
|
|
|
|
|
May 10 2016, 09:43
|
Местный
  
Группа: Участник
Сообщений: 301
Регистрация: 13-12-15
Из: Харьков
Пользователь №: 89 682

|
Цитата(scifi @ May 10 2016, 11:13)  Код, который для вас кажется ожидаемым, для кого-то другого легко может быть неожиданным. Я не имею ввиду себя или еще кого-то конкретно. Ожидаемый - с точки зрения формальной логики: если b=~а то-> ~b == а. Цитата(halfdoom @ May 10 2016, 11:49)  Пример немного не об этом, но уж раз вы завели речь о разрядной сетке - при использовании uint8_t вместо short все равно будет расширение типа до int, хотя результат помещается в short. Я описал только первый вариант Вашего примера потому что для второго, где short, действия совершенно аналогичны - в силу того, что разряд суммы выходит за пределы двухбайтной сетки. Но в обоих случаях тип операнда для ~ уже не является типом разрядности short по априори, до выполнения самой арифметической операции с необходимостью расширения операндов. В принципе, все сводится к случаю, когда источником операнда для ~ является lvalue-значение.
|
|
|
|
2 чел. читают эту тему (гостей: 2, скрытых пользователей: 0)
Пользователей: 0
|
|
|