Отговори на тема  [ 17 мнения ]  Отиди на страница 1, 2  Следваща
Data types convertions 
Автор Съобщение
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Вто Дек 14, 2004 1:31 pm
Мнения: 3849
Мнение Data types convertions
Скоро се отвори в една тема вьпросът. При мен се получава следното омазване.
В документацията на компилатора C166 пише
Цитат:
Data types are automatically converted when the result implies another data type

Какво се получава в действителност. Следният код на C.
Код:
void some_func(void)
{ static unsigned int b;   
  unsigned int ad;

  ad = T2;
  ad -= b;
  b = T2;
  frequency_real = (unsigned long)ad * 7;
}

Сьответно кода на Асемблер:

MOV    R6, DPP3:0x3E40 //ad = T2
SUB    R6, DPP2:0x3C96 //ad -= b
MOV    DPP2:0x3C96, T2 //b = T2
MOV    R4, #0x07
MULU   R6, R4
MOV    DPP2:0x3C8E, MDH
MOV    DPP2:0x3C8C, MDL


frequency_real е голбална променлива от тип unsigned long. Всичко е нормално, компилаторьт разбира, че резултатьт от умножението ще инициализира 32bit-oва променлива и използва MD регистьр-а.
Какво става обаче ако малко модифицирам кода, като "забравя" да конвертирам рьчно. Все пак се предполага, чe компилаторьт трябва да сьобрази последното. На последния обаче не му идва на ум, че резултатьт implies another data type и ще се наложи да се сьхрани в 32bit-ова променлива и прави слената глупост.

Код:
void some_func(void)
{ static unsigned int b;   
  unsigned int ad;

  ad = T2;
  ad -= b;
  b = T2;
  frequency_real = ad * 7;
}

MOV    R6, DPP3:0x3E40 //ad = T2
SUB    R6, DPP2:0x3C96 //ad -= b
MOV    DPP2:0x3C96, T2 //b = T2
MOV    R4, R6
MOV    R6, R4
SHL    R4, #0x03
SUB    R4, R6
MOV    R5, #0x00
MOV    DPP2:0x3C8C, R4
MOV    DPP2:0x3C8E, R5


Спестява ми много интелигентно мултиплицирането и записва в cтаршите 16bit-а 0x0000, келеш :) Иди после тьрси грешката, добре че е листинга.


Чет Апр 05, 2007 2:34 pm
Профил WWW
Ранг: Почетен член
Ранг: Почетен член
Аватар

Регистриран на: Пет Фев 17, 2006 9:17 am
Мнения: 765
Местоположение: Стара Загора
Мнение 
Keil-а редовно прави такива простотии. Понякокага дори се налага да си правиш междинни променливи с явно преобразуване на тип.... иначе маркуча. :evil: Абе лайна с помия е този кеил, кой каквото и да разправя.


Чет Апр 05, 2007 2:50 pm
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Нед Окт 31, 2004 9:19 pm
Мнения: 4464
Местоположение: Stara Zagora
Мнение 
не вдявам от този асемблер и не ми се гадае но от гледна точка на C
frequency_real = (unsigned long)ad * 7;
трябва да стане следното
- ad се преобразува до unsigned long
след което резултата от това преобразуване се умножава по 7 тоест имаме unsigned long * unsigned long като резултата от тази операция е unsigned long.
След това се каства до unsigned int и това се присвоява на frequency_real. Ако компилатора е направил друго значе е бъг.


Чет Апр 05, 2007 5:53 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Вто Дек 14, 2004 1:31 pm
Мнения: 3849
Мнение 
Цитат:
След това се каства до unsigned int и това се присвоява на frequency_real.


frequency_real е от тип unsigned long. А компилаторьт в този пример, горния, реагира доста интелигентно, като мултиплицира два 16bit-ови регистьра и сьхранява 32bit-овия резултат в MD регистьра, и това с една инструкция MULU, бива си го контролерчето.
Проблемьт е в долния код, там кьдето липсва (unsigned long). В този случай умножава стойността в 16bit-овия регистьр с 7, като шифтва 3 пьти в ляво и изважда ведньж стойността на регистьра от резултата, и това всичко го записва в ниските 2 байта на 32bit-овата глобална frequency_real, а старшите 2 байта нулира. Тоест резултата е 16bit-ов, за мен това е бьг. И обeца на ухото, навсякьде да слагам едно рьчно конвертиране от рода на (unsigned long) кьдето боравя с променливи от различен вид.


Чет Апр 05, 2007 6:08 pm
Профил WWW
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Фев 26, 2006 6:52 pm
Мнения: 11266
Местоположение: Добрич
Мнение 
Да не се изложа ама мисля че ВСЕКИ компилатор ще постъпи по тоя начин. Имаш:

Цитат:
frequency_real = ad * 7;


Преобразуването по тип се прави по повод конкретна операция, а ти имаш ДВЕ операции, едната умножение - другата присвояване.
По задължение първо се извършва умножение, което е между два uint, значи и операцията ще е такава.
Втората операция е присвояване, тогава това което е отдявсно се каства до каквото пише вляво...


Чет Апр 05, 2007 6:16 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Вто Дек 14, 2004 1:31 pm
Мнения: 3849
Мнение 
Така като го обясняваш звучи доста логично. Опитах с 7L вместо 7 и работата заспа. А аз оплюх компилтатора, тя била в мен грешката :oops:


Чет Апр 05, 2007 6:24 pm
Профил WWW
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Съб Сеп 25, 2004 12:32 pm
Мнения: 8382
Местоположение: София
Мнение 
miro_atc написа:
Да не се изложа ама мисля че ВСЕКИ компилатор ще постъпи по тоя начин. Имаш:

Цитат:
frequency_real = ad * 7;


Преобразуването по тип се прави по повод конкретна операция, а ти имаш ДВЕ операции, едната умножение - другата присвояване.
По задължение първо се извършва умножение, което е между два uint, значи и операцията ще е такава.
Втората операция е присвояване, тогава това което е отдявсно се каства до каквото пише вляво...


Константите, мисля, по стандарт бяха int. Тая седмица е int със знак. Стойността на целия израз, доколкото помня, беше с типа на първия операнд.


Чет Апр 05, 2007 10:30 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Нед Окт 31, 2004 9:19 pm
Мнения: 4464
Местоположение: Stara Zagora
Мнение 
Да по стандарт типа на резултата е типа на първия операнд със сигурност.
И това че типа на константите е int също е по стандарта май.
Но на практика съм забелязал че не се спазва,от IAR за AVR поне съм сигурен. Използва се тип при който кода е най ефективен.
В случая мисля че най ефективно би било да е unsigned int но всъщност може и да греша. Но като цяло не би трябвало в случая типа на константата да влияе на резултата. Евентуално на оптималноста на кода само.


Чет Апр 05, 2007 10:58 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Нед Ное 21, 2004 11:31 pm
Мнения: 10088
Мнение 
и затова се ползва винаги явно преобразуване на типовете.
за да се елиминира влиянието на диалекта и преводача

ПС: стандартите са приемат, за да не се спазват :P


Пет Апр 06, 2007 8:47 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Фев 26, 2006 6:52 pm
Мнения: 11266
Местоположение: Добрич
Мнение 
Реконструктор написа:
Стойността на целия израз, доколкото помня, беше с типа на първия операнд.


Не съм съгласен... Типът на резултата се определя от типовете на операндите без значение, кой е първи и кой е втори.
Умножение на int с int дава int, умножение на uint с int дава int, умножение на int с лонг дава лонг....
Поне така е в математиката, а който не вярва за програмирането може да провери че a*b == b*a //независимо от типовете на а и b

Иначе това което казваш се отнася до това кой операнд се извлича първи - левия или десния, ама това е една друга приказка...


Пет Апр 06, 2007 10:13 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Нед Окт 31, 2004 9:19 pm
Мнения: 4464
Местоположение: Stara Zagora
Мнение 
но при програмирането е намесена и размерноста на типовете
x = a*b от математиката
при програмирането е x = (а*b) & 0xFF
да кажем за случай на променливи от тип unsigned char.


Пет Апр 06, 2007 11:15 am
Профил
Ранг: Почетен член
Ранг: Почетен член
Аватар

Регистриран на: Пет Фев 17, 2006 9:17 am
Мнения: 765
Местоположение: Стара Загора
Мнение 
Принципно кеила не се справя с преобразуването на типове както трябва. Изрази от сорта на if (float<int) или дори if (float <0) го затрудняват сериозно. float винаги се оказва по-малко (или по-голямо, не помня какво) :weedman: Не помага дори и If (float < (float) int). Решението е единствено

float temp;
temp=(float) int;
if (float <temp)

Ако искаш кода ти да работи винаги де... Изрази от сорта на a=-b; също са ми създавали проблеми. Уоркароунд: а=0; а-=b;

Олигофрении колкото искаш.


Пет Апр 06, 2007 12:04 pm
Профил ICQ
Ранг: Форумен бог
Ранг: Форумен бог

Регистриран на: Нед Фев 26, 2006 6:52 pm
Мнения: 11266
Местоположение: Добрич
Мнение 
Nikola Kirov написа:
но при програмирането е намесена и размерноста на типовете
x = a*b от математиката
при програмирането е x = (а*b) & 0xFF
да кажем за случай на променливи от тип unsigned char.


то и в математиката е същото бе Никола, ако си дефинираш че работиш в подмножество X (0<=х<=255) от множеството на целочислените числа, си оставаш в това подмножество...

Така че, твърдението:
Цитат:
Да по стандарт типа на резултата е типа на първия операнд със сигурност.

е вярно само за операции с един операнд и някои операции при които позицията на операндите има значение.

За прости симетрични операции като събиране/умножение - не е вярно ;-)
Обратното би означавало A*B да е различно от B*A, когато А и В са от различни типове...

Примерно ако:
unsigned char a=5;
unsigned int b=100;
unsigned int ab, ba;

ab = a*b;
ba = b*a;


Според теб излиза че ab=244 , ba =500 - което очевидно не е така ;-)


Пет Апр 06, 2007 1:12 pm
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Нед Окт 31, 2004 9:19 pm
Мнения: 4464
Местоположение: Stara Zagora
Мнение 
Да прав си.

Но в такъв случай трябва да има някакво правило.
Какъв ще е резултата например от
(unsigned int * signed int) операция


Вто Апр 10, 2007 11:02 am
Профил
Ранг: Форумен бог
Ранг: Форумен бог
Аватар

Регистриран на: Съб Сеп 25, 2004 12:32 pm
Мнения: 8382
Местоположение: София
Мнение 
Nikola Kirov написа:
Да прав си.

Но в такъв случай трябва да има някакво правило.
Какъв ще е резултата например от
(unsigned int * signed int) операция


Каства се към типа на променливата, на която се присвоява. Например, -1 * 1 = 4294967295 (0xFFFFFFFF)


Вто Апр 10, 2007 11:20 am
Профил
Покажи мненията от миналия:  Сортирай по  
Отговори на тема   [ 17 мнения ]  Отиди на страница 1, 2  Следваща

Кой е на линия

Потребители разглеждащи този форум: 0 регистрирани и 2 госта


Вие не можете да пускате нови теми
Вие не можете да отговаряте на теми
Вие не можете да променяте собственото си мнение
Вие не можете да изтривате собствените си мнения
Вие не можете да прикачвате файл

Търсене:
Иди на:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group.
Designed by ST Software for PTF.
Хостинг и Домейни