Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Детская ошибка
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
Страницы: 1, 2, 3, 4
amiller
Недавно столкнулся с одной странностью (по крайней мере для меня). Хотелось бы понять.
Есть фрагмент года (упрощенный до безобразия):
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
AleksBak
А если так:
Код
int16u temp1, temp2;
    for (int32u i = 0; i < 10; i++)
    {
        temp1 = 0x0001;
        temp2 = 0xFFFE;
        if ( (int16u)(~temp1) != temp2 ) continue;
        temp2 = temp1;
    }
amiller
Цитата(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;
    }

Так как Вы предлагаете, тоже работает. Хотя в этом меня тоже смущает один момент. После выполнения оператора "~" не должна меняться размерность переменной.
Но больше всего меня беспокоит результат компиляции первого моего примера. В ассемблерном коде вообще отсутствует условный оператор и всё, что после него.
И при этом никаких предупреждений от компилятора.
Как это можно рассматривать? Бага компилятора? Или есть более простое объяснение?
Сергей Борщ
QUOTE (amiller @ May 2 2016, 10:16) *
После выполнения оператора "~" не должна меняться размерность переменной.
Может меняться и после и до. В данном случае меняется до. Читайте про неявные приведения типов (implicit type conversion) и правила расширения целых (integer promotion rules).
QUOTE (amiller @ May 2 2016, 10:16) *
Как это можно рассматривать? Бага компилятора? Или есть более простое объяснение?
Как обычно (в 99.99% случев) - компилятор не виноват, просто программист не удосужился изучить язык, который пытается использовать.
amiller
Цитата(Сергей Борщ @ 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
Сергей Борщ
QUOTE (amiller @ May 2 2016, 10:36) *
Ну а судя по второй фразе, Вы точно знаете причину по которой компилятор удаляет часть кода, и при этом нет ни одного предупреждения?
Так сообщите пожалуйста. Мне это по прежнему непонятно. Речь идёт о самом первом примере.
Да, знаю. После выполнения расширения типов ваше условие выполняется всегда, для любых значений переменных temp1 и temp2 (0xFFFFxxxx всегда не равно 0x0000xxxx). Поэтому условие всегда истинно и проверять его не имеет смысла - вы же хотите, чтобы ваша программа была маленькой и быстрой, поэтому компилятор просто выкинул бессмысленную проверку и весь код, который никогда, ни при каких условиях выполняться не будет.
amiller
Цитата(Сергей Борщ @ May 2 2016, 11:09) *
Да, знаю. После выполнения расширения типов ваше условие выполняется всегда, для любых значений переменных temp1 и temp2 (0xFFFFxxxx всегда не равно 0x0000xxxx). Поэтому условие всегда истинно и проверять его не имеет смысла - вы же хотите, чтобы ваша программа была маленькой и быстрой, поэтому компилятор просто выкинул бессмысленную проверку и весь код, который никогда, ни при каких условиях выполняться не будет.

Позволю себе усомниться по двум пунктам:
1. Раньше во всех случаях, когда в коде был фрагмент, который никогда не выполняется, я получал от компилятора соответствующее предупреждение. В данном случае - нет.
2. Я уже писал, что если переменные объявить как int32u, то условие тоже всегда истинно. Но в этом случае компилятор не выбрасывает из кода условный оператор и всё что после него.
Есть вероятность, что ответ на этот простой вопрос, как обычно, лежит в более сложных материях.
Кстати уровень оптимизации = Null, поэтому с этой стороны не следует ожидать от компилятора излишней предупредительности.
scifi
Цитата(amiller @ May 2 2016, 10:16) *
Но больше всего меня беспокоит результат компиляции первого моего примера. В ассемблерном коде вообще отсутствует условный оператор и всё, что после него.

Вы будете смеяться, но компилятор вовсе не обязан на каждый чих в исходнике генерить код. Обычно на минимальном уровне оптимизации генерит, но тоже не всегда и не везде. Компилятор отвечает только за то, что сгенерированный код выдаст тот результат, который следует из исходника. Если исходник никакого результата не подразумевает, то компилятор может не генерировать ничего - и будет в своём праве.

Цитата(amiller @ May 2 2016, 11:21) *
1. Раньше во всех случаях, когда в коде был фрагмент, который никогда не выполняется, я получал от компилятора соответствующее предупреждение. В данном случае - нет.

Это вам показалось. Если припомните, какое именно было предупреждение, то поймёте, что в данном случае оно не применимо. А если не припомните, то это просто испорченный телефон. Короче, показалось.

Цитата(amiller @ May 2 2016, 11:21) *
Но в этом случае компилятор не выбрасывает из кода условный оператор и всё что после него.
Есть вероятность, что ответ на этот простой вопрос, как обычно, лежит в более сложных материях.

Не надо там искать сложных материй. В одном случае выкинул бессмысленный код, в другом - нет. Подумаешь - бывает сплошь и рядом. Компилятор - это просто программа, а не какое-то высшее существо с высшим разумом.
amiller
Цитата(scifi @ May 2 2016, 14:26) *
Вы будете смеяться, но компилятор вовсе не обязан на каждый чих в исходнике генерить код. Обычно на минимальном уровне оптимизации генерит, но тоже не всегда и не везде. Компилятор отвечает только за то, что сгенерированный код выдаст тот результат, который следует из исходника. Если исходник никакого результата не подразумевает, то компилятор может не генерировать ничего - и будет в своём праве.

В этом с Вами я согласен, но предупредить то надо. Например если поставить внутри функции безусловный return, генерится предупреждение. А в данном случае всё происходит молча. Ну и не совсем понятен алгоритм. В одном случае молча выбрасывает код, а в другом очень похожем случае всё же генерит код, который тем не менее также не выполняется.

Например, если в том же примере заменить строку с условным оператором "if (true) continue;" то получаем предупреждение:
Warning[Pe111]: statement is unreachable - что логично. А в моем примере это происходило "молча".

Тем не менее всем спасибо!
Ошибка локализована. И с утверждением, что компилятор "не обязан", я согласен. Остальное в общем то уже нюансы функционирования программы, которой также является и компилятор.
AleksBak
Цитата(amiller @ May 2 2016, 15:35) *
В этом с Вами я согласен, но предупредить то надо. Например если поставить внутри функции безусловный return, генерится предупреждение. А в данном случае всё происходит молча. Ну и не совсем понятен алгоритм. В одном случае молча выбрасывает код, а в другом очень похожем случае всё же генерит код, который тем не менее также не выполняется.
...

Я было подумал, что IAR-овский компилер тут и поэтому может так, а оказывается и gcc аналогично себя ведет в этой ситуации.
Цитата(amiller @ May 2 2016, 15:35) *
... И с утверждением, что компилятор "не обязан", я согласен...

Почему? Ведь мог и написать что-то. Но нет промолчал как рыба.
GetSmart
Цитата(amiller @ May 2 2016, 15:35) *
В этом с Вами я согласен, но предупредить то надо.

Зря соглашаетесь. Хороший компилятор (и некий стандарт предупреждений) должен уметь определять опечатки и вероятные ошибки. Согласие в данном случае с тем, что он не обязан.

Обнаружил как-то у себя код
Код
{
bla bla bla;
bla bla bla;
} while (++i<10);

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

----

Но "стандарт предупреждений" неудачное название. История показывает, что каждый (американский) стандартер желает наВрать, где сидит фазан. Лучше "правила" с приоритетами.
Опечатку выделил. Опечатался буквой си.
Baser
Цитата(GetSmart @ May 2 2016, 16:49) *
Обнаружил как-то у себя код ...
В котором в первой строке перед скобкой пропущен do. Просматривая такой код, ошибка не особо и видна. А компилятору заметить здесь что-то неладное совсем не сложно. Абыдно.

Пример вы выбрали для подтверждения своей мысли сильно неудачный. Ибо и без do и с do конструкция совершенно легальна, хотя и имеет различную логику работы. А телепатическими способностями, чтобы понять то, что вы не написали, компиляторы уж точно не обладают sm.gif
ViKo
Цитата(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);
Огурцов
Цитата(GetSmart @ May 2 2016, 13:49) *
Хороший компилятор (и некий стандарт предупреждений) должен уметь определять опечатки и вероятные ошибки. Согласие в данном случае с тем, что он не обязан.

хороший - обязан (выдать предупреждение), сишный - не обязан
jcxz
Цитата(GetSmart @ May 2 2016, 19:49) *
Код
{
bla bla bla;
bla bla bla;
} while (++i<10);

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

И что в этом коде неладно???
Следуя Вашей логике, компилятор на выражение:
int x;
тоже должен выдавать варнинг, ведь может Вы там хотели написать:
unsigned int x;
Компилятор не должен думать за программиста.
GetSmart
Цитата(jcxz @ May 3 2016, 19:33) *
И что в этом коде неладно???

Это должен был быть цикл на 10 итераций с выпрыгиванием из него при определённых обстоятельствах. А получилась только одна итерация.

Искренне считаю, что обнаруживать такую СТРАННУЮ последовательность должен компилятор. Правило: если идёт свободный блок, за которым while без тела, то выдать варнинг. Иначе на while без тела с неволатильными переменными в условии выдавать ремарку. Тело в данном случае - ключевой признак этих правил.

Цитата(Baser @ May 2 2016, 20:18) *
Пример вы выбрали для подтверждения своей мысли сильно неудачный.

Именно такие странности хотелось бы чтобы компилятор "подчёркивал" при компиляции, как Ворд подчёркивает текст при просмотре. Пример тот самый. Как и у ТС.
zltigo
QUOTE (GetSmart @ May 3 2016, 19:23) *
Искренне считаю, что обнаруживать такую СТРАННУЮ последовательность должен компилятор. Правило: если идёт свободный блок, за которым while без тела, то выдать варнинг.

Блок может использоваться по причинам совершенно не связанным с ошибкой - локализация объявления переменной, макроподстановка...
Так что не надо стенаний, особенно, если стеной стоите, как мне помится, на "нормальности" while(константа){} sm.gif


GetSmart
Цитата(zltigo @ May 3 2016, 23:47) *
Так что не надо стенаний, особенно, если стеной стоите, как мне помится, на "нормальности" while(константа){} sm.gif

while / if (const) ==> ремарка. Продолжаю считать, как и ранее. Полезные конструкции. С тремя уровнями сообщений компилятора. То бишь с двумя не препятствующими генерации прошивки.

В идеале на pred_while(1) и post_while(0) даже ремарку не выдавать. Если макроса в скобках не было.

Цитата(zltigo @ May 3 2016, 23:47) *
Блок может использоваться по причинам совершенно не связанным с ошибкой - локализация объявления переменной, макроподстановка...

Макроподстановку легко обнаружить и учесть. Логика на порядки проще оптимизации кода.
aiwa
Вообще-то да, это работа не компилятора, но редактора.
Вернее, той особо развитой в последнее его части, которая анализирует код, делает автозавершение, производит выравнивание и прочее.
Вот с его точки зрения легко предположить отсутствие начала в шаблоне do{}while();
Tahoe
Цитата(amiller @ May 2 2016, 14:35) *
Ошибка локализована. И с утверждением, что компилятор "не обязан", я согласен. Остальное в общем то уже нюансы функционирования программы, которой также является и компилятор.

1. Странно, что локализована. Лично мне резануло глаз присваивание константы в цикле, при том что константа объявлена не volatile. Стало быть, весь цикл вообще теряет смысл. И никакие неявные приведения типов тут вообще ни причем.

2. Упрощения, это хорошо. Но приводить упрощенный Си-код вне функции, дело бесполезное. Хотя бы потому, что не понятно, переменные temp1 и temp2 локальные или глобальные.

3. Насчет обязан или не обязан компилер. Конечно не обязан, его дело компилировать. Зато статический анализатор кода сразу завопил бы, с негодованием. Благо в последних IAR встроен C-Stat. Настоятельно рекомендую натравить его на код. Гарантирую(с), он еще много "чудес" выявит в коде. wink.gif
amiller
Цитата(Tahoe @ May 6 2016, 07:58) *
1. Странно, что локализована. Лично мне резануло глаз присваивание константы в цикле, при том что константа объявлена не volatile. Стало быть, весь цикл вообще теряет смысл. И никакие неявные приведения типов тут вообще ни причем.
2. Упрощения, это хорошо. Но приводить упрощенный Си-код вне функции, дело бесполезное. Хотя бы потому, что не понятно, переменные temp1 и temp2 локальные или глобальные.

Если ошибка воспроизводится в такой простой конструкции, то зачем присылать страницы кода?
Переменные temp1 и temp2 локальные, объявление на строчку выше. В исходном коде переменным присваиваются не константы, а результат, возвращаемый функцией. А после условного оператора ещё сотня строк в цикле.
Меня лично смутило, что компилятор без предупреждений выбросил из программы большой фрагмент кода. Это было главное, на что я обратил внимание.
Но раз общественность не забилась в праведном гневе, значит все считают это нормальным. А тогда вопрос и не стоит обсуждать.
Тем более в коде был грешок с приведением типов, на который мне правильно указали.

Tahoe
Цитата(amiller @ May 6 2016, 09:23) *
Если ошибка воспроизводится в такой простой конструкции, то зачем присылать страницы кода?

Еще раз. Нет никакой конструкции. Тот огрызок, что приведен, не позволяет нормально определить источник проблемы.

Цитата(amiller @ May 6 2016, 09:23) *
Переменные temp1 и temp2 локальные, объявление на строчку выше. В исходном коде переменным присваиваются не константы, а результат, возвращаемый функцией.

"Не в преферанс, а в лотерею. Не миллион, а пять тыщ. И не выиграл, а проиграл." (с)

Я только не понял, это вот "в исходном коде не константы", это просто поприкалываться захотелось или на полном серьезе?

Цитата(amiller @ May 6 2016, 09:23) *
Но раз общественность не забилась в праведном гневе, значит все считают это нормальным. А тогда вопрос и не стоит обсуждать.Тем более в коде был грешок с приведением типов, на который мне правильно указали.

А, общественность... Все считают... Тогда другое дело. Это заявка на успех. Желаю удачи.
scifi
Цитата(Tahoe @ May 6 2016, 11:32) *
Еще раз. Нет никакой конструкции. Тот огрызок, что приведен, не позволяет нормально определить источник проблемы.

Да ладно, нормальный огрызок. Вот словесное описание путаное, это да. Но вроде бы сразу понятно, что всё упирается в неявное приведение типов и устранение лишнего кода.
Короче, не надо занудствовать, с проблемой уже разобрались.
amiller
Цитата(Tahoe @ May 6 2016, 11:32) *
Еще раз. Нет никакой конструкции. Тот огрызок, что приведен, не позволяет нормально определить источник проблемы.


"Не в преферанс, а в лотерею. Не миллион, а пять тыщ. И не выиграл, а проиграл." (с)

Я только не понял, это вот "в исходном коде не константы", это просто поприкалываться захотелось или на полном серьезе?


А, общественность... Все считают... Тогда другое дело. Это заявка на успех. Желаю удачи.


Извините, но я не понял к чему это всё, что Вы написали.
Или Вы считаете, что если я скопирую сюда полный код функции, Вы точно укажете на источник проблемы? Или Вы считаете, что я школьник, и то, что я прислал к делу не имеет отношения, а ошибка в другом месте?
Смею Вас заверить, что это не так.
И проблема воспроизводится именно в том "огрызке", который я разместил, я специально проверял. Для этого больше ничего не нужно, достаточно этот фрагмент разместить в пустом main(). Ну разве что скорректировать названия типов.
И в отзывах была информация, что это характерно не только для компилятора IAR. В gcc тоже проблема воспроизводится.
zltigo
QUOTE (amiller @ May 6 2016, 11:58) *
И в отзывах была информация, что это характерно не только для компилятора IAR. В gcc тоже проблема воспроизводится.

Опять sad.gif. Да не проблема это компилятора, ЛЮБОЙ компилятор ОБЯЗАН поступить аналогично. Это АБСОЛЮТНО Ваша проблема связанная с незнаним языка.
amiller
Цитата(zltigo @ May 6 2016, 16:44) *
Опять sad.gif. Да не проблема это компилятора, ЛЮБОЙ компилятор ОБЯЗАН поступить аналогично. Это АБСОЛЮТНО Ваша проблема связанная с незнаним языка.

Я нигде не писал, что претендую на звание "гуру". Более того, на ошибках учусь с удовольствием, как на своих, так и на чужих.
Но никто не дал на мой вопрос чёткий ответ.
1. Если переменные int16u, то компилятор код выбрасывает. У меня нет вопросов к самому факту этого события. У меня вопрос к тому, почему это происходит без предупреждения (молча). Я не считаю, что это нормальное поведение компилятора.
2. Однако если переменные int32u, то с точки зрения выполнения кода ничего не меняется. Но тем не менее в этом случае, код компилируется (не выбрасывается). Хотя результат также предопределен и известен заранее.
Я уже вроде успокоился по этому поводу, но находятся всё новые люди, которые утверждают, что я не знаю язык, но не дают чёткого ответа, почему компилятор поступает именно так.
Может Вы попробуете?

scifi
Цитата(amiller @ May 6 2016, 17:19) *
1. Если переменные int16u, то компилятор код выбрасывает. У меня нет вопросов к самому факту этого события. У меня вопрос к тому, почему это происходит без предупреждения (молча).

Предупреждения придуманы для удобства. Они помогают отловить ошибки в коде. Нет никаких стандартов, регламентирующих поведение компилятора в этом вопросе. Более того, авторы компилятора тоже никаких обязательств здесь на себя не берут. Следовательно, вопрос "почему" довольно бесперспективный. Если вас так уж гложет, вам надо добыть исходники этого компилятора и разобраться, что там происходит. Или спросить того, кто делает этот компилятор. В этом форуме, понятное дело, вы таких не найдёте.

Цитата(amiller @ May 6 2016, 17:19) *
2. Однако если переменные int32u, то с точки зрения выполнения кода ничего не меняется. Но тем не менее в этом случае, код компилируется (не выбрасывается). Хотя результат также предопределен и известен заранее.
Я уже вроде успокоился по этому поводу, но находятся всё новые люди, которые утверждают, что я не знаю язык, но не дают чёткого ответа, почему компилятор поступает именно так.

Здесь применим тот же ответ, что я дал выше. "Нет никаких стандартов, регламентирующих поведение компилятора в этом вопросе" и далее по тексту.

В общем, не те вопросы задаёте, не о том думаете. Кстати, именно вот эти неправильные вопросы и дают людям повод усомниться в вашем знании языка Си.
Tahoe
Цитата(amiller @ May 6 2016, 17:19) *
1. Если переменные int16u, то компилятор код выбрасывает.

Последний раз, больше даже пытаться не стану. Если десять раз присвоить константу temp1=0x1, хоть что-то изменится, хоть на одном проходе из 10? Если не изменится, то бишь даже без всякой оптимизации, temp1 и temp2 _всегда_ будут иметь одно и то же значение. Результат if (~0x0001!= 0xFFFE) будет отличаться хоть на одном из проходов? И плевать какие там типы, все 10 раз будет одно и то же. А строчка temp2 = temp1; будет вообще игнорироваться.

В итоге, имеем несколько строчек бессмысленного кода, который вырождается в пару присваиваний. И никакого цикла здесь нет. Другой вопрос, когда вместо констант будет присваиваться результат функции. В этом случае, может и дойдет до кривых типов. Но в приведенном куске, с константами, до этого дело даже не доходит.
Сергей Борщ
QUOTE (amiller @ May 6 2016, 17:19) *
2. Однако если переменные int32u, то с точки зрения выполнения кода ничего не меняется.
Меняется. При приведении int16_t -> int32_t происходит расширение знака.
amiller
Цитата(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 (не зависит от типа переменных), но в одном случае код компилируется, а в другом выбрасывается.
Tahoe
Цитата(amiller @ May 7 2016, 05:52) *
Представленный фрагмент кода имеет только один смысл - продемонстрировать наличие проблемы в действиях компилятора.

Представленный фрагмент ничего не демонстрирует, от слова "вообще". Особенно, проблем с компилером. Единственное, что он демонстрирует, это лень и, как следствие, дурную манеру изложения, в стиле "Рабинович напел".
amiller
Цитата(Tahoe @ May 7 2016, 08:14) *
Представленный фрагмент ничего не демонстрирует, от слова "вообще". Особенно, проблем с компилером. Единственное, что он демонстрирует, это лень и, как следствие, дурную манеру изложения, в стиле "Рабинович напел".

А кроме голословных утверждений Вам есть что сообщить? В чём именно заключается лень или дурные манеры?
Чтобы убедиться в том, а чём я пишу, достаточно:
1. Вставить в программу фрагмент кода (соответствующим образом изменив названия типов).
2. Откомпилировать. Убедиться, что начиная с условного оператора в листинге код не формируется, а предупреждений не выдается.
3. Поменять типы на int32u (или uint32_t, как удобно).
4. Снова откомпилировать,убедиться, что в листинге код есть, хотя результат условного оператора также предопределен, как и в первом случае.
5. Задуматься, возможно сделать выводы.
6. Если понятна причина такого поведения компилятора, рассказать автору вопроса.
7. Если причина неизвестна, то лучше промолчать, а не опускаться до стиля "сам дурак".
aiwa
Цитата(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;

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

Одноразовое изделие - одно, о нём и темы нет. Как только нужна переносимость кода весь геморрой - ваш.
Если соломку не стелить регулярно.
Темы о глюках компиляторов, стандартах и их (не)соблюдении вечны как и холивар.
zltigo
QUOTE (svss @ May 7 2016, 12:24) *
не полагаться на компилятор /что он все приведения типов и приоритеты операций соблюдёт/

Вообще то он СОБЛЮДЕТ! Лет 25 уже основные компиляторы сколь-нибудь явных ошибок НЕ допускают.
QUOTE
Расставляйте скобки и явные касты. (это не я придумал: жизнь учит)

А вот это скоерее, да. Только НЕ для компилятора, а для себя, ибо в отличие от компилятора человку сложнее держать в голове те же 15 уровней приоритета.
Но и маниакально распихивать скобки и приведения типов тоже не дело.
Tahoe
Цитата(amiller @ May 7 2016, 08:37) *
А кроме голословных утверждений Вам есть что сообщить?
...
2. Откомпилировать. Убедиться, что начиная с условного оператора в листинге код не формируется, а предупреждений не выдается.

Я все сообщил еще в своем первом ответе. И почему код отсутствует, и что запустить, что бы увидеть желаемое предупреждение.

Код, приведенный в первом посте - бессмысленный. С какой стати компилер должен предупреждать об этом? Это широко распространенный прием, например при условной компиляции, когда часть кода намеренно превращается бессмысленное. С какой стати компилеру лезть не в свое дело? Откуда он знает, это программер бестолково пишет, как в данном случае или код заточен под 100500 вариантов? А вот статический анализатор, тот не просто предупредит, вопить будет. Однако отсутствие вопросов и комментариев по статическому анализатору, говорит о том, что даже не понятно, о чем вообще речь. Так может, чем продолжать дерзить, запустить хоть раз C-STAT или хотя бы выяснить, что это такое?
amiller
Цитата(Tahoe @ May 7 2016, 16:47) *
Так может, чем продолжать дерзить, запустить хоть раз C-STAT или хотя бы выяснить, что это такое?

Ну извините пожалуйста. Я сразу не обратил внимание, что Вы из Москвы. Простите молодого пятидесятилетнего провинциала, что я вообще вступил с Вами в дискуссию.
Мне надо было посыпать голову пеплом и с восторгом внимать Вам.
Только напомните мне пожалуйста, что именно Вы сказали по существу конкретного вопроса, который я задал?
Tahoe
Цитата(amiller @ May 7 2016, 17:04) *
сразу не обратил внимание, что Вы из Москвы. Простите молодого пятидесятилетнего провинциала

Не понял, как это относится к запуску C-STAT, зато стало ясно, что имею дело с очередным не признанным гением. В этом месте позвольте откланяться. Удачи.
Огурцов
Цитата(scifi @ May 6 2016, 16:29) *
Предупреждения придуманы для удобства. Они помогают отловить ошибки в коде. Нет никаких стандартов, регламентирующих поведение компилятора в этом вопросе. Более того, авторы компилятора тоже никаких обязательств здесь на себя не берут.

странно, в одном случае берут, в другом таком же - не берут
а не проще ли было писать компилятор так, что во всех случаях выдавать предупреждение, а не когда как
amiller
Цитата(Tahoe @ May 7 2016, 19:06) *
Не понял, как это относится к запуску C-STAT, зато стало ясно, что имею дело с очередным не признанным гением. В этом месте позвольте откланяться. Удачи.

Как же Вы любите ярлыки навешивать... Вообще то мои слова появились в ответ на Ваше "продолжать дерзить".
По моему Вы вообще не поняли, о чём идёт речь.
1. Я не прошу помощи в написании кода или в оценке его качества.
2. Не нужно советов по использованию дополнительного ПО, так как это совсем не относится к делу.
3. И речь не шла о правильности или эффективности примера, его (примера) задача - продемонстрировать описанную проблему.
В своем сообщении я описал проблему в работе компилятора, которую увидел.
И хотел выяснить нормальное это поведение или нет и почему компилятор ведёт себя по разному в похожих случаях.
А конкретная задача в написании программы была решена ещё до того, как было написано сообщение.
Ведь не все вопросы обязаны быть на тему "помогите, не работает...".
scifi
Цитата(Огурцов @ May 7 2016, 19:57) *
а не проще ли было писать компилятор так, что во всех случаях выдавать предупреждение, а не когда как

Не знаю. Сколько компиляторов вы сделали? Я - ни одного. Потому и не знаю.
aiwa
Цитата(Огурцов @ May 7 2016, 19:57) *
а не проще ли было писать компилятор так, что во всех случаях выдавать предупреждение, а не когда как

Та тут как бы компилятор и не виноват, он всего лишь следует предписаниям стандарта.
Даже дело не в в отсутствии предупреждения, в нарушении законов булевой алгебры.
Но желание преемственности побеждает здравый смысл.


Огурцов
вы можете между собой договориться, есть в предписании стандарта речь про предупреждения или нет ?
aiwa
Цитата(Огурцов @ May 8 2016, 00:59) *
вы можете между собой договориться, есть в предписании стандарта речь про предупреждения или нет ?

А о чем должно быть предупреждение?
В сухом остатке получается переменная булевого типа, равная нулю. А само нарушение закона двойного отрицания происходит
в процессе обработки выражения.
Причем, в старых 16-битных компиляторах обработка происходит корректно.

zltigo
QUOTE (aiwa @ May 8 2016, 01:31) *
Причем, в старых 16-битных компиляторах обработка происходит корректно.

Маразм процветает sad.gif. Причем тут "старые", или "новые" - в огороде бузина а в Киеве дядька sad.gif. Компиляция такого "примера" зависит от разрядности int целевой платформы и ни от чего более.

ViKo
Прочитав тему еще раз, понял, что топикстартер привел гипотетический пример, который и не пробовал компилировать. И народ кинулся обсуждать, приводить доводы за и против для того, что в реальности невозможно.
Предлагаю выдать проверенный компилятором исходный текст.
Огурцов
Цитата(aiwa @ May 7 2016, 22:31) *
А о чем должно быть предупреждение?

о своих действиях - выбросил код, обнаружил невыполняемый или недостижимый код - сообщи
jcxz
Цитата(Огурцов @ 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. Сообщать?
...и т.п.
ViKo
Цитата(Огурцов @ May 8 2016, 09:05) *
о своих действиях - выбросил код, обнаружил невыполняемый или недостижимый код - сообщи

Он так и сделает, будьте patient.
У Кейла есть ключик компилятора -remarks. И тогда он мне кидает больше сотни предупреждений. Один недостаток, трудно сообщения об ошибках искать. Задаю поиск "error". sm.gif
Может, ИАР тоже так может?
jcxz
Цитата(ViKo @ May 8 2016, 12:18) *
У Кейла есть ключик компилятора -remarks. И тогда он мне кидает больше сотни предупреждений. Один недостаток, трудно сообщения об ошибках искать. Задаю поиск "error". sm.gif
Может, ИАР тоже так может?

IAR всё может. Только какая польза от такого кол-ва предупреждений, если среди них трудно найти полезные и всё равно их приходится отключать?
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.