amiller 2 2 мая, 2016 Опубликовано 2 мая, 2016 (изменено) · Жалоба Недавно столкнулся с одной странностью (по крайней мере для меня). Хотелось бы понять. Есть фрагмент года (упрощенный до безобразия): 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. И код работает как надо только в таком варианте: 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 Изменено 2 мая, 2016 пользователем amiller Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AleksBak 0 2 мая, 2016 Опубликовано 2 мая, 2016 · Жалоба А если так: int16u temp1, temp2; for (int32u i = 0; i < 10; i++) { temp1 = 0x0001; temp2 = 0xFFFE; if ( (int16u)(~temp1) != temp2 ) continue; temp2 = temp1; } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amiller 2 2 мая, 2016 Опубликовано 2 мая, 2016 · Жалоба А если так: int16u temp1, temp2; for (int32u i = 0; i < 10; i++) { temp1 = 0x0001; temp2 = 0xFFFE; if ( (int16u)(~temp1) != temp2 ) continue; temp2 = temp1; } Так как Вы предлагаете, тоже работает. Хотя в этом меня тоже смущает один момент. После выполнения оператора "~" не должна меняться размерность переменной. Но больше всего меня беспокоит результат компиляции первого моего примера. В ассемблерном коде вообще отсутствует условный оператор и всё, что после него. И при этом никаких предупреждений от компилятора. Как это можно рассматривать? Бага компилятора? Или есть более простое объяснение? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 123 2 мая, 2016 Опубликовано 2 мая, 2016 · Жалоба После выполнения оператора "~" не должна меняться размерность переменной.Может меняться и после и до. В данном случае меняется до. Читайте про неявные приведения типов (implicit type conversion) и правила расширения целых (integer promotion rules). Как это можно рассматривать? Бага компилятора? Или есть более простое объяснение?Как обычно (в 99.99% случев) - компилятор не виноват, просто программист не удосужился изучить язык, который пытается использовать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amiller 2 2 мая, 2016 Опубликовано 2 мая, 2016 (изменено) · Жалоба Может меняться и после и до. В данном случае меняется до. Читайте про неявные приведения типов (implicit type conversion) и правила расширения целых (integer promotion rules). Как обычно - компилятор не виноват, просто программист не удосужился изучить язык, который пытается использовать. Про неявное приведение типов соглашусь. Ну а судя по второй фразе, Вы точно знаете причину по которой компилятор удаляет часть кода, и при этом нет ни одного предупреждения? Так сообщите пожалуйста. Мне это по прежнему непонятно. Речь идёт о самом первом примере. Поясняю ещё раз. Дело не в том, что результат выполнения условной операции неверный. Дело в том, что условный оператор не выполняется вообще. В исходной программе после этого условного оператора у меня было под сотню строк кода до окончания цикла. И весь этот код отсутствует в ассемблере. \ 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 Изменено 2 мая, 2016 пользователем amiller Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 123 2 мая, 2016 Опубликовано 2 мая, 2016 · Жалоба Ну а судя по второй фразе, Вы точно знаете причину по которой компилятор удаляет часть кода, и при этом нет ни одного предупреждения? Так сообщите пожалуйста. Мне это по прежнему непонятно. Речь идёт о самом первом примере. Да, знаю. После выполнения расширения типов ваше условие выполняется всегда, для любых значений переменных temp1 и temp2 (0xFFFFxxxx всегда не равно 0x0000xxxx). Поэтому условие всегда истинно и проверять его не имеет смысла - вы же хотите, чтобы ваша программа была маленькой и быстрой, поэтому компилятор просто выкинул бессмысленную проверку и весь код, который никогда, ни при каких условиях выполняться не будет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amiller 2 2 мая, 2016 Опубликовано 2 мая, 2016 · Жалоба Да, знаю. После выполнения расширения типов ваше условие выполняется всегда, для любых значений переменных temp1 и temp2 (0xFFFFxxxx всегда не равно 0x0000xxxx). Поэтому условие всегда истинно и проверять его не имеет смысла - вы же хотите, чтобы ваша программа была маленькой и быстрой, поэтому компилятор просто выкинул бессмысленную проверку и весь код, который никогда, ни при каких условиях выполняться не будет. Позволю себе усомниться по двум пунктам: 1. Раньше во всех случаях, когда в коде был фрагмент, который никогда не выполняется, я получал от компилятора соответствующее предупреждение. В данном случае - нет. 2. Я уже писал, что если переменные объявить как int32u, то условие тоже всегда истинно. Но в этом случае компилятор не выбрасывает из кода условный оператор и всё что после него. Есть вероятность, что ответ на этот простой вопрос, как обычно, лежит в более сложных материях. Кстати уровень оптимизации = Null, поэтому с этой стороны не следует ожидать от компилятора излишней предупредительности. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
scifi 1 2 мая, 2016 Опубликовано 2 мая, 2016 · Жалоба Но больше всего меня беспокоит результат компиляции первого моего примера. В ассемблерном коде вообще отсутствует условный оператор и всё, что после него. Вы будете смеяться, но компилятор вовсе не обязан на каждый чих в исходнике генерить код. Обычно на минимальном уровне оптимизации генерит, но тоже не всегда и не везде. Компилятор отвечает только за то, что сгенерированный код выдаст тот результат, который следует из исходника. Если исходник никакого результата не подразумевает, то компилятор может не генерировать ничего - и будет в своём праве. 1. Раньше во всех случаях, когда в коде был фрагмент, который никогда не выполняется, я получал от компилятора соответствующее предупреждение. В данном случае - нет. Это вам показалось. Если припомните, какое именно было предупреждение, то поймёте, что в данном случае оно не применимо. А если не припомните, то это просто испорченный телефон. Короче, показалось. Но в этом случае компилятор не выбрасывает из кода условный оператор и всё что после него. Есть вероятность, что ответ на этот простой вопрос, как обычно, лежит в более сложных материях. Не надо там искать сложных материй. В одном случае выкинул бессмысленный код, в другом - нет. Подумаешь - бывает сплошь и рядом. Компилятор - это просто программа, а не какое-то высшее существо с высшим разумом. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amiller 2 2 мая, 2016 Опубликовано 2 мая, 2016 (изменено) · Жалоба Вы будете смеяться, но компилятор вовсе не обязан на каждый чих в исходнике генерить код. Обычно на минимальном уровне оптимизации генерит, но тоже не всегда и не везде. Компилятор отвечает только за то, что сгенерированный код выдаст тот результат, который следует из исходника. Если исходник никакого результата не подразумевает, то компилятор может не генерировать ничего - и будет в своём праве. В этом с Вами я согласен, но предупредить то надо. Например если поставить внутри функции безусловный return, генерится предупреждение. А в данном случае всё происходит молча. Ну и не совсем понятен алгоритм. В одном случае молча выбрасывает код, а в другом очень похожем случае всё же генерит код, который тем не менее также не выполняется. Например, если в том же примере заменить строку с условным оператором "if (true) continue;" то получаем предупреждение: Warning[Pe111]: statement is unreachable - что логично. А в моем примере это происходило "молча". Тем не менее всем спасибо! Ошибка локализована. И с утверждением, что компилятор "не обязан", я согласен. Остальное в общем то уже нюансы функционирования программы, которой также является и компилятор. Изменено 2 мая, 2016 пользователем amiller Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
AleksBak 0 2 мая, 2016 Опубликовано 2 мая, 2016 · Жалоба В этом с Вами я согласен, но предупредить то надо. Например если поставить внутри функции безусловный return, генерится предупреждение. А в данном случае всё происходит молча. Ну и не совсем понятен алгоритм. В одном случае молча выбрасывает код, а в другом очень похожем случае всё же генерит код, который тем не менее также не выполняется. ... Я было подумал, что IAR-овский компилер тут и поэтому может так, а оказывается и gcc аналогично себя ведет в этой ситуации. ... И с утверждением, что компилятор "не обязан", я согласен... Почему? Ведь мог и написать что-то. Но нет промолчал как рыба. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GetSmart 0 2 мая, 2016 Опубликовано 2 мая, 2016 (изменено) · Жалоба В этом с Вами я согласен, но предупредить то надо. Зря соглашаетесь. Хороший компилятор (и некий стандарт предупреждений) должен уметь определять опечатки и вероятные ошибки. Согласие в данном случае с тем, что он не обязан. Обнаружил как-то у себя код { bla bla bla; bla bla bla; } while (++i<10); В котором в первой строке перед скобкой пропущен do. Просматривая такой код, ошибка не особо и видна. А компилятору заметить здесь что-то неладное совсем не сложно. Абыдно. ---- Но "стандарт предупреждений" неудачное название. История показывает, что каждый (американский) стандартер желает наВрать, где сидит фазан. Лучше "правила" с приоритетами. Опечатку выделил. Опечатался буквой си. Изменено 2 мая, 2016 пользователем GetSmart Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Baser 5 2 мая, 2016 Опубликовано 2 мая, 2016 · Жалоба Обнаружил как-то у себя код ... В котором в первой строке перед скобкой пропущен do. Просматривая такой код, ошибка не особо и видна. А компилятору заметить здесь что-то неладное совсем не сложно. Абыдно. Пример вы выбрали для подтверждения своей мысли сильно неудачный. Ибо и без do и с do конструкция совершенно легальна, хотя и имеет различную логику работы. А телепатическими способностями, чтобы понять то, что вы не написали, компиляторы уж точно не обладают :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 2 мая, 2016 Опубликовано 2 мая, 2016 · Жалоба Обнаружил как-то у себя код { bla bla bla; bla bla bla; } while (++i<10); В котором в первой строке перед скобкой пропущен do. Просматривая такой код, ошибка не особо и видна. А компилятору заметить здесь что-то неладное совсем не сложно. Абыдно. Ой ли? { bla bla bla; bla bla bla; } while (++i<10); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
VCucumber 0 2 мая, 2016 Опубликовано 2 мая, 2016 · Жалоба Хороший компилятор (и некий стандарт предупреждений) должен уметь определять опечатки и вероятные ошибки. Согласие в данном случае с тем, что он не обязан. хороший - обязан (выдать предупреждение), сишный - не обязан Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 197 3 мая, 2016 Опубликовано 3 мая, 2016 · Жалоба { bla bla bla; bla bla bla; } while (++i<10); В котором в первой строке перед скобкой пропущен do. Просматривая такой код, ошибка не особо и видна. А компилятору заметить здесь что-то неладное совсем не сложно. Абыдно. И что в этом коде неладно??? Следуя Вашей логике, компилятор на выражение: int x; тоже должен выдавать варнинг, ведь может Вы там хотели написать: unsigned int x; Компилятор не должен думать за программиста. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться