|
|
  |
Проблемы c IAR AVR! |
|
|
|
Nov 21 2006, 11:31
|
Группа: Новичок
Сообщений: 3
Регистрация: 7-11-06
Пользователь №: 22 049

|
Имеется IAR 4.20. Выполняю небольшую программу и угадайте, что я получаю на выходе??? 32640+4294934528!!
unsigned long int L1=0,L2=0; unsigned char C1;
int main( void ) { C1=0x80; L1=C1*255; L2=C1*256; return (L1+L2); }
В Borland C++, Visual Studio результат правильный! Только не надо говорить, что надо писать так или C1 должно быть Long Int! L2=(long int)C1*256;
Как правильно настроить IAR????
|
|
|
|
|
Nov 21 2006, 14:22
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(GDI @ Nov 21 2006, 13:58)  Именно так L2=(long int)C1*256; можно еще L2=(long int)256*C1; или L2=0х00000100*C1; А в Борланде и VC вычисления всегда в int идут, причем int там 4 байта. Все правильно, только можно чуть короче L2 = C1 * 256L; А в Borland и в VC действительно тип int эквивалентен типу long. Тип int изначально был аппаратно-зависим, т.е. разрядность данных этого типа выбиралась такой, чтобы операции с данными этого типа выполнялись наиболее естественным, для выбранного процессора, образом.
|
|
|
|
|
Nov 22 2006, 09:39
|
Частый гость
 
Группа: Свой
Сообщений: 151
Регистрация: 21-02-06
Пользователь №: 14 561

|
Цитата(arttab @ Nov 21 2006, 13:43)  Придется правильно писать, поскольку сначало делаются вычисления, а потом приведение к типу ...вообще-то можно типами оперировать и во время вычислений Цитата(Yura_Kyiv @ Nov 21 2006, 12:31)  Имеется IAR 4.20. Выполняю небольшую программу и угадайте, что я получаю на выходе??? 32640+4294934528!!
unsigned long int L1=0,L2=0; unsigned char C1;
int main( void ) { C1=0x80; L1=C1*255; L2=C1*256; return (L1+L2); }
В Borland C++, Visual Studio результат правильный! Только не надо говорить, что надо писать так или C1 должно быть Long Int! L2=(long int)C1*256;
Как правильно настроить IAR???? ...странновато, потому что в процессе вычисления выражения компилятор сам должен приводить типы, в данном случае к unsigned long int, может компилятор кривой? ...попробуй в опциях для компилятора указать Strict ISO/ANSI
|
|
|
|
|
Nov 22 2006, 10:18
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(tag @ Nov 22 2006, 09:39)  ...странновато, потому что в процессе вычисления выражения компилятор сам должен приводить типы, в данном случае к unsigned long int, может компилятор кривой? ...попробуй в опциях для компилятора указать Strict ISO/ANSI Компилятор тут ни при чем. Он правильно все делает, он приводит к старшему типу, в соответствии с типом одного из операндов. А вот результат операции перед присваиванием приводится к типу данных в левой части выражения. Но если результат операции уже неправильный (при переполнении), то это приведение ничего не изменит.
|
|
|
|
|
Nov 22 2006, 11:26
|
Группа: Новичок
Сообщений: 3
Регистрация: 7-11-06
Пользователь №: 22 049

|
Цитата(tag @ Nov 22 2006, 08:39)  ...странновато, потому что в процессе вычисления выражения компилятор сам должен приводить типы, в данном случае к unsigned long int, может компилятор кривой? ...попробуй в опциях для компилятора указать Strict ISO/ANSI Strict ISO/ANSI - не помогает! К великому сожалению в опциях компилятора IAR для 8-разрядного процессора нельзя задать, что бы внутренние математические операции шли на уровне Long Int  , а не Int. Поэтому 128*256= -32768. Высшая математика от IAR при содействии AVR
|
|
|
|
|
Nov 22 2006, 12:34
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(Yura_Kyiv @ Nov 22 2006, 11:26)  Strict ISO/ANSI - не помогает! К великому сожалению в опциях компилятора IAR для 8-разрядного процессора нельзя задать, что бы внутренние математические операции шли на уровне Long Int  , а не Int. Поэтому 128*256= -32768. Высшая математика от IAR при содействии AVR  Можно задать компилятору, чтобы действия выполнялись не только типа long, но и double.
|
|
|
|
|
Nov 22 2006, 12:34
|

Частый гость
 
Группа: Свой
Сообщений: 175
Регистрация: 26-01-06
Из: Sevastopol
Пользователь №: 13 664

|
Цитата(_Bill @ Nov 22 2006, 09:18)  Компилятор тут ни при чем. Он правильно все делает, он приводит к старшему типу, в соответствии с типом одного из операндов. Хотел тоже написать нечто вроде этого. Однако, имея привычку писать то, в чем уверен (или писать с оговоркой), копнул стандарт языка. И вот что там обнаружил (см. выделенное мною): Цитата Type Conversions
Within several contexts the translator converts the type of a scalar expression (or subexpression). The conversions are called:
* promoting * balancing * assigning * type casting
This section describes each of these conversions and the context in which it occurs. It also shows how the translator determines the value of the converted type from the value of the original type.
Promoting
Except when it is the operand of the sizeof operator, an integer rvalue expression has one of four types:
* int * unsigned int * long * unsigned long
When you write an expression in an rvalue subcontext and the expression has an integer type that is not one of these types, the translator promotes its type. If all of the values representable in the original type are also representable as type int, then the promoted type is int. Otherwise, the promoted type is unsigned int.
Thus, for signed char, short, and any signed bitfield type, the promoted type is int. For each of the remaining integer types (char, unsigned char, unsigned short, any plain bitfield type, or any unsigned bitfield type), the effect of these rules is to favor promoting to int wherever possible, but to promote to unsigned int if necessary to preserve the original value in all possible cases.
For example:
signed char ch; unsigned short us, f(char *, ...); f("%i%x", ch, // ch becomes int us); // us becomes int or unsigned int
Balancing
When you write an infix operator that has two arithmetic rvalue operands, the translator frequently determines the type of the result by balancing the types of the two operands. To balance two types, the translator applies the following rules to the promoted types of the operands:
* Unless the two types are unsigned int and long, the balanced type is the promoted type (of the two) that occurs later in the sequence: int, unsigned int, long, unsigned long, float, double, and long double. * If the two types are unsigned int and long and the type long can represent all values of type unsigned int, the balanced type is long. * Otherwise, the balanced type is unsigned long.
Each of the operands is converted to the balanced type, the arithmetic operation occurs between the now identical types, and the result of the operation has the balanced type. For example:
int i; long lo; double d; return ((i + lo) // i becomes long + d); // (i + lo) becomes double Иначе говоря, согласно вышесказанному, если имеется выражение с разными целочисленными типами справа, то каждый из операндов должен быть преобразован к одному из названных типов - в данном случае это int или unsigned int. С этой точки зрения нельзя не согласиться с Yura_Kyiv, что имеет место отклонение от стандарта. С другой стороны, такая трактовка на 8-битных системах существенным образом снизит эффективность вычислений. Изменить это можно явным приведением типа вроде (int)C1 или т.п. А вот при обратном поведении компилятора это было бы неподконтрольно. И с этой точки зрения разработчики IAR дают возможность явно указать свои намерения программисту. Не стану утверждать, что они неправы. Я не уверен, что они не придерживаются какого-нибудь более нового стандарта C или Embedded C, где это оговорено. Но со своей стороны скажу, что лично я никогда не рассчитываю на подобные автоматические конверсии типов. Если есть основания допускать, что результат выражения с операндами типа char выйдет за рамки char - лучше самому явно привести типы к максимально возможному (Balancing) и не надеяться на то, что на данной платформе конкретный компилятор сделает это за программиста, причем, вполне определенным образом.
|
|
|
|
|
Nov 22 2006, 13:02
|

Частый гость
 
Группа: Свой
Сообщений: 175
Регистрация: 26-01-06
Из: Sevastopol
Пользователь №: 13 664

|
Еще раз посмотрел выражение: увы, компилятор IAR ведет себя в полном соответствии со стандартом языка C. Выставить иск не выйдет. Готов показать это.
Имеем в выражении "L2=C1*256" два операнда: unsigned char C1=128 и число 256.
В соответствии с правилом "If all of the values representable in the original type are also representable as type int, then the promoted type is int. Otherwise, the promoted type is unsigned int" получаем, что оба этих операнда независимо друг от друга преобразуются к типу int:
128 представимо типом int? Да. 256 представимо типом int? Да.
Далее имеем операцию со сбалансированными (идентичными) типами операндов: оба операнда имеют тип int (не long и не unsigned int). Выражение также имеет тип int. Но происходит переполнение - результат равен 32768, или -1 с точки зрения типа int.
Ну а дальше следует преобразование типов при присваивании int к unsigned long. Знак расширяется при переходе от int к long int, а потом теряется при присваивании long int к unsigned long int. И получаем те самые FFFF8000 (которое 4294934528).
В полном соответствии со стандартом. А на x86 платформе этот номер проходит, поскольку int там занимает 4 байта, и 32768 вписывается в него, чего не происходит при 2-байтном int. А это уже нюанс, определяемый реализацией, как было замечено.
Резюме: явно указывать преобразования типов. Хуже от этого никогда не будет, а таких вот ошибок можно будет избежать. Не говоря уже о том, что другим читать такую программу будет на порядок проще.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|