Неявное и непонятное приведение типов

Все о микроконтроллерах: AVR, PIC, STM8, STM32, Arduino, Altera, Xilinx, все что угодно. Этот раздел для всего что клацает байтиками.
Аватара пользователя
BSVi
Адепт
Сообщения: 3576
Откуда: Киев

Сообщение BSVi » 14 сен 2013, 17:53

Почти час потратил на выискивание такой, казалось бы мелочной штуки. Внимание, код:

Код: Выделить всё

uint16 geta() { return 2; }
uint16 getb() { return 0xFFFD; }
bool cmp() { return geta() == ~getb(); }


Да, я заранее проверил что 2 == ~0xFFFD, но как вы думаете, что вернет cmp() ? А cmp() возвращает всегда false. Причина в неявном и непонятном приведении типа. ~getb() cстановится int'ом, хотя сам getb() был uint16. Если переписать вот так

Код: Выделить всё

uint16 geta() { return 2; }
uint16 getb() { return 0xFFFD; }
bool cmp() { return geta() == (uint16)~getb(); }


То все работает. Внимание вопрос - откуда берется такое хитрое преобразование типов?

uschema.com
Сообщения: 162

Сообщение uschema.com » 14 сен 2013, 18:00

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

Аватара пользователя
BSVi
Адепт
Сообщения: 3576
Откуда: Киев

Сообщение BSVi » 14 сен 2013, 18:06

Мне кажется, что это не баг - и Visual Studio и IAR ведут себя абсолютно одинаково. Одинаковый баг в обоих компиляторах выглядит довольно подозрительно.

uschema.com
Сообщения: 162

Сообщение uschema.com » 14 сен 2013, 18:11

на електроникс.ру, эдак в 2007м, мы обсуждали много таких моментов, и их было оооой как много.
там даже ребята олдовые на спор приводили куски кода для воспроизведения подобных багов, забавная была тема.
в результате, все как один пришли к такому же выводу что я описал.

tomatniy
Сообщения: 70
Откуда: Киев

Сообщение tomatniy » 14 сен 2013, 20:29

в принципе рассматривая ~ как обычную функцию(очевидно у неё будут на входе и выходе int) или пусть даже как asm команду - поведение по-моему логичное, но к сожалению архитектуро-зависимое :)

Аватара пользователя
BSVi
Адепт
Сообщения: 3576
Откуда: Киев

Сообщение BSVi » 14 сен 2013, 20:45

На ru_embedded разобрались. Ошибся, как не странно, я. Как оказывается, при арифметических операциях, компилятор приводит все типы, меньше чем int к int'у (ну, или если тип не может вместиться в int, то к unsigned int'у). И только потом выполняется арифметическая операция.

Вот тут статья, которая подробно объясняет что и как.

Там даже очень похожий пример есть.

Vasiliy_Br
Сообщения: 11

Сообщение Vasiliy_Br » 02 ноя 2013, 00:07

ПОсмотрите пожалуйста код, как думаете , как можно сделать красивее? Это фунция на вход получает значение счетчика таймера на котором энодер, выдает адаптированное значение ,приращение значение зависит от скорости вращения энкодера.

Код: Выделить всё

uint16_t smart_encoder(uint16_t iner){
    static char i;
    static uint16_t tmp=0, result=0;
    static int accum =0;
    int diff = ((((int)tmp)<<16)-(((int)iner)<<16))>>16; //эта строчка работает правильно, но сама не красива, может кто знает решение?
    //int16_t diff = (int16_t)tmp-(int16_t)iner; //эта строчка не работает, при переходе iner ч 0 в 0xFFFF и назад получается ерунда
    if (diff>0) accum += diff;
    else accum -= diff;
    tmp=iner;
    if (-diff*(accum)<=(int)result) result+=diff*(accum);
    else result=0;
    //accum>>=(1);
    accum>>=(++i&1);
    return result;
}

Аватара пользователя
BSVi
Адепт
Сообщения: 3576
Откуда: Киев

Сообщение BSVi » 02 ноя 2013, 00:42

это как-то относится к теме топика?

Vasiliy_Br
Сообщения: 11

Сообщение Vasiliy_Br » 02 ноя 2013, 18:38

Я спрошу по другому. СТМ32 ГЦЦ.

Код: Выделить всё

uint16_t smart_encoder(uint16_t iner){
   ...
    static uint16_t tmp=0;
    int diff = (int16_t)tmp-(int16_t)iner;
   ...
   tmp=iner;
    ...
}


при iner=0xFF и tmp=1 я ожидаю , что при операции вычитания, в любом порядке, я получу + или - 2 , но почему то получается что то около 65534

uschema.com
Сообщения: 162

Сообщение uschema.com » 02 ноя 2013, 19:49

1 - уже сама по себе декларация переменной и тут же присваивание значения через какие то мат операции не есть "гудвэй" (такое на ура прокатывает в С++, но не желательно в С, так как компилеры часто лажают). Однако для GCC такое поведение странное, чет мне кажется это с подачи стмовских патчей
2 - int diff - намёк

Вернуться в «Микроконтроллеры и ПЛИС»



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

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