Перейти к содержанию
    

Интересный глюк в CodeVisionAVR

Обнаружил интересный глюк в CodeVision, целый день вчера просидел - думал во мне дело, оказалось, что нет.

Если мы делаем сдвиг и результирующее число выходит из размера 1 байта, то, почему-то, компилятор не преобразует его к int (хотя обязан по стандарту). То есть вот такой код работает непрявильно:

unisigned char s = 243;
//...
unsigned int d = (unsigned int)(s << 4);  // d != 3888

 

а надо так делать, что глупо...

 

unisigned char s = 243;
//...
unsigned int d = (unsigned int)(((unsigned int)s) << 4);  // d = 3888

 

Интересно, зачем это надо или это просто баг??..

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Да, выходит, это еще одно несоответствие стандарту этого компилятора.

Можно написать проще:

unsigned int d = (unsigned int)s << 4;

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Обнаружил интересный глюк в CodeVision, целый день вчера просидел - думал во мне дело, оказалось, что нет.

unisigned char s = 243;
//...
unsigned int d = (unsigned int)(s << 4);  // d != 3888

А по моему - все правилно делает компилятор:

 

1. Выполняется выражение в скобках - 8-бит переменная сдвигается на четыре бита влево

 

2. Результат преобразуется к беззнаковому целому.

 

 

 

А вот так:

 

 unisigned char s = 243;
//...
unsigned int d = (unsigned int)(((unsigned int)s) << 4);  // d = 3888

 

1. Выполняется выражение во внутренних скобках - s преобразуется к беззнаковому целому.

 

2. Выполняется выражение во внешних скобках - 16-бит беззнаковое целое сдвигается на четыре бита влево

 

3. Результат преобразуется к беззнаковому целому

 

 

 

Все правильно :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А по моему - все правилно делает компилятор:
"По-вашему" - вполне вероятно. Но по стандарту должно быть иначе:

6.3.1 Arithmetic operands

6.3.1.1 Boolean, characters, and integers

....

2 The following may be used in an expression wherever an int or unsigned int may be used:

— An object or expression with an integer type whose integer conversion rank is less than the rank of int and unsigned int.

— A bit-field of type _Bool, int, signed int,or unsigned int.

If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions. All other types are unchanged by the integer promotions.

И раз есть отличие от стандарта, то оно должно быть явно указано в документации (например, в документации на микрочиповский C18 такое описание есть). А если в документации оно не упомянуто, то, извините, или бага или этот компилятор не может называться "компилятором языка высокого уровня С"

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Обнаружил интересный глюк в CodeVision, целый день вчера просидел - думал во мне дело, оказалось, что нет.

Если мы делаем сдвиг и результирующее число выходит из размера 1 байта, то, почему-то, компилятор не преобразует его к int (хотя обязан по стандарту). То есть вот такой код работает непрявильно:

unisigned char s = 243;
//...
unsigned int d = (unsigned int)(s << 4);  // d != 3888

 

Никогда бы и в голову не прошло так приводить типы,естесвенней и проше как написал Сергей.

И насчет компилятора-все-ж написано чистым английским языком:

 

it is important to note that if the Project|Configure|C Compiler|Code Generation|Promote char to int option isn't checked or the #pragma promotechar+ isn't used, the char, respectively unsigned char, type operands are not automatically promoted to int , respectively unsigned int, as in compilers targeted for 16 or 32 bit CPUs.

This helps writing more size and speed efficient code for an 8 bit CPU like the AVR.

To prevent overflow on 8 bit addition or multiplication, casting may be required.

The compiler issues warnings in these situations.

 

Варнинги то хоть генерились,или они подавлены?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

"По-вашему" - вполне вероятно. Но по стандарту должно быть иначе:

И раз есть отличие от стандарта, то оно должно быть явно указано в документации (например, в документации на микрочиповский C18 такое описание есть). А если в документации оно не упомянуто, то, извините, или бага или этот компилятор не может называться "компилятором языка высокого уровня С"

Сорри, ошибся :a14:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

или этот компилятор не может называться "компилятором языка высокого уровня С"

А он и так не является компилятором C. В C нет возможности писать вещи вроде PORTA.0=1, нет конструкции interrupt[wtf] и ещё много чего. Даже в C99.

Поэтому только avr-gcc.

 

--

WBR, Andrew

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ворнинги не генерились, что и странно. А насчет того, чтобы пользоваться опцией Project|Configure|C Compiler|Code Generation|Promote char to int - так это изврат, по-моему.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Обнаружил интересный глюк в CodeVision, целый день вчера просидел - думал во мне дело, оказалось, что нет.

Уже обсуждалось. "Выбрось каку".

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Выбрось каку ;)

 

Прошу не пинать -- прошелся поиском по сайту и нашел сто-0-олько тем про глюконат-кодевижина, что прям ой! Вобщем, пощщу (от сл. "постить") в первый попавшийся топик по глюкам.

 

Сегодня приспичило меня поднять старые исходники, которые я еще писал в CodeVision в хз каком мохнатом году... Думал, закопипащщу (опять, гы-гы) текст в ИАР, подправлю где надо порты/регистры и вперед! Тема-то изъезженная вдоль и поперек -- подключение текстового LCD. Чего тут думать-то!? Ан, нет! Старые грабли с новыми ручкам...

 

Короче, IAR обнаружил ошибку на выходе из функции. Стыдно признаться, но это так, -- моя невнимательность. Но меня другое плющит -- Codevision эту ошибку в упор не видит. Пф-ф!

 

Вот код функции (слегка урезанный):

//
//  Перевод кодировки Win-1251 в LDC-кодировку
//
BYTE _Translate(BYTE data)
{
  switch (data)
  {
  case 'Ё':
    return 0xA2;
  case 'ё':
...
  case '№':
    return 0xCC;
  case '\\':
    return 0xFF;
  }

  if (data >= 0xC0)
    return rus[data - 0xC0];
}

 

Для молодых поэтов поясняю -- собака порылась в последнем операторе if.

 

Вопрос: что будет, если data будет меньше 0xC0? Какой код вернет функция? Правльный выход из функции должен быть, разумеется, такой:

...
  if (data >= 0xC0)
    return rus[data - 0xC0];
  else
    return data;
}

 

(Может кому пригодится. Хех!)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно написать проще:

unsigned int d = (unsigned int)s << 4;

Можно написать еще проще

unsigned int d = s << 4;

зачем делать приведение типа в правой части, если в левой части и так unsigned int.

 

к тому же

Все операнды типа unsigned char или unsigned short преобразуются в тип unsigned int.

 

 

разумеется, такой:

Неочевидно, потому что ваш пример вообще неоткомилируется, неизвестно что такое rus :)

 

Очень странно как вы использовали этот код и не наткнулись на проблему раньше, ведь 3/4 символов, в т.ч. и цифры, были недоступными!

 

По теме CV согласен - фтопку этот недоинструмент.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можно написать еще проще

unsigned int d = s << 4;

зачем делать приведение типа в правой части, если в левой части и так unsigned int.

Если опустить integer promotion rules, которые CV не соблюдает, то в остальном в этом выражении он действует по стандарту: сначала вычисляется правая часть, потом ее результат приводится к левой части. То, что вы написали другими словами можно представить примерно так:

unsigned int s = 0x1234;
unsigned long d = s << 4;

зачем делать приведение типа в правой части, если в левой части и так unsigned long.

 

Но меня другое плющит -- Codevision эту ошибку в упор не видит. Пф-ф!
gcc без -Wall тоже пропускает такое. В свое время тоже был удивлен, когда старые проекты, писаные в оболочке Dev-C++ стал собирать со своим рукописным makefile. Тоже решил тогда для себя "нафиг оболочку, теперь makefiles только руками".

А с -Wall gcc выдает не ошибку, а предупреждение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вопрос: что будет, если data будет меньше 0xC0? Какой код вернет функция?
Все зависит от того, что вы выкинули заменив точечками в switch'e возможно за этот if управление даже не выйдет.

Кстати, насколько я припоминаю, у КодеВижена есть настройка какие варнинги выводить, а какие нет. Надо там глянуть не отключены ли.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Уже обсуждалось. "Выбрось каку".

 

Кака, конечно.

Но если бы в IAR C было также просто вставлять ассемблерный код в текс программы как это сделано в CvAVR... :crying:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но если бы в IAR C было также просто вставлять ассемблерный код в текс программы как это сделано в CvAVR... :crying:
Тогда вам в gcc. Такого шикарного инлайн-асма в других компиляторах не встречалось. Вставленный код не мешает оптимизатору, компилятор сам решает, в каких регистрах удобнее передать параметры в ваш ассемблерный кусок... Конфетка! Не знаю как CV, но ИАР встретив в функции инлайн-асм складывает крылья и выключает оптимизатор (где-то в описании было).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...