реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Как в Си определить выход за пределы кода (переполнение) результата операции ?
MaxiMuz
сообщение Apr 23 2013, 18:38
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



Элементарная ситуация: Имеется два 16-битных числа , при их сложении нужно отслеживать ситуацию переполнения результата.
Пробую:
Код
uint16_t temp16;
uint16_t sumADC;

if ((sumADC+=temp16)>0xffff)
     { // Отключение АЦП  !!
         ADCSRA=(1<<ADEN);}

понимаю что это нет то ....
Нужно как можно короче превести это к коду (для AVR):
Код
add rd_l,rs_l
adc rd_h,rs_h
brcs m1
....

Как это все оформляется в Си ?

Сообщение отредактировал MaxiMuz - Apr 23 2013, 19:18
Go to the top of the page
 
+Quote Post
arttab
сообщение Apr 24 2013, 01:06
Сообщение #2


Профессионал
*****

Группа: Свой
Сообщений: 1 432
Регистрация: 7-12-04
Из: Новосибирск
Пользователь №: 1 371



а по флагу переполнения не проще ли?


--------------------
OrCAD, Altium,IAR, AVR....
Go to the top of the page
 
+Quote Post
maksimp
сообщение Apr 24 2013, 03:09
Сообщение #3


Местный
***

Группа: Участник
Сообщений: 313
Регистрация: 2-07-11
Пользователь №: 66 023



Такой именно ассемблерный код как вы хотите может быть и не получится.
Варианты:
Код
unit16_t x=sumADC;
sumADC+=temp16;
if (x>0xffffU-temp16)

Код
unit16_t x=sumADC;
sumADC+=temp16;
if (((unit32_t)x+temp16)>0xffffUL)

Код
unit32_t x=sumADC+temp16;
sumADC=(unit16_t)x;
if (x>0xffffUL)
Go to the top of the page
 
+Quote Post
VslavX
сообщение Apr 24 2013, 05:14
Сообщение #4


embarrassed systems engineer
*****

Группа: Свой
Сообщений: 1 083
Регистрация: 24-10-05
Из: Осокорки
Пользователь №: 10 038



Можно попробовать так:
Код
uint16_t temp16;
uint16_t sumADC;

sumADC+=temp16;
if (sumADC < temp16)
{
     { // Отключение АЦП  !!

Но ассемблерного варианта скорее всего тоже не получится.
Go to the top of the page
 
+Quote Post
Alexey K
сообщение Apr 24 2013, 05:54
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 46
Регистрация: 14-07-11
Пользователь №: 66 220



CODE

uint16_t temp16;
uint16_t sumADC;
uint32_t sum32;

sum32 = sum32 + temp16;

if ( sum32 <= 0xFFFFFFFF )
{
sumADC = (uint16_t) sum32;
}
else
{
//overflow actions
}


Сообщение отредактировал Alexey K - Apr 24 2013, 05:56
Go to the top of the page
 
+Quote Post
Vetal-Soft
сообщение Apr 24 2013, 05:58
Сообщение #6


Участник
*

Группа: Участник
Сообщений: 60
Регистрация: 16-06-05
Пользователь №: 6 074



Код
if ((0xffff-sumADC) < temp16)
      {  . . .
Go to the top of the page
 
+Quote Post
ViKo
сообщение Apr 24 2013, 05:58
Сообщение #7


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



А что, arttab дал плохой совет? Доступ к флагам имеется?
Go to the top of the page
 
+Quote Post
ARV
сообщение Apr 24 2013, 05:59
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581



Цитата(Alexey K @ Apr 24 2013, 09:54) *
CODE

uint16_t temp16;
uint16_t sumADC;
uint32_t sum32;

sum32 = sum32 + temp16;

if ( sum32 <= 0xFFFFFFFF )
{
sumADC = (uint16_t) sum32;
}
else
{
//overflow actions
}
ну, все-таки скорее всего чуть-чуть иначе:
CODE

uint16_t temp16;
uint16_t sumADC;
uint32_t sum32;

sum32 = sum32 + temp16;

if ( sum32 <= 0xFFFF ) // переполнение-то для 16-бит надо отслеживать
{
sumADC = sum32;
}
else
{
//overflow actions
}


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
Alexey K
сообщение Apr 24 2013, 06:01
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 46
Регистрация: 14-07-11
Пользователь №: 66 220



Согласен. Утро однакоsm.gif
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Apr 24 2013, 07:00
Сообщение #10


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



А при сравнении флаг С учитывается?
Иначе крайние варианты не катят

Тьфу, пардон, uint32 же..


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Apr 24 2013, 07:49
Сообщение #11


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(ARV @ Apr 24 2013, 09:59) *
Код
uint32_t sum32;
В avr-gcc 4.7.x имеется тип __uint24

Цитата(ViKo @ Apr 24 2013, 09:58) *
А что, arttab дал плохой совет? Доступ к флагам имеется?

Имеется. Просто обращение к SREG по маске
Код
if (SREG & (1<<n)) {...}

Лучше всю эту красоту завернуть в макрос типа:
Код
#define add16_sat(a,b) \
do \
{ \
   (a) += (b); \
   if (SREG & (1<<SREG_C)) \
   { \
      (a) = -1U; \
   } \
} while (0)


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Apr 25 2013, 10:05
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



Цитата(maksimp @ Apr 24 2013, 06:09) *
Такой именно ассемблерный код как вы хотите может быть и не получится.
Варианты:
Код
unit16_t x=sumADC;
sumADC+=temp16;
if (x>0xffffU-temp16)

Код
unit16_t x=sumADC;
sumADC+=temp16;
if (((unit32_t)x+temp16)>0xffffUL)

Код
unit32_t x=sumADC+temp16;
sumADC=(unit16_t)x;
if (x>0xffffUL)

введение дополнительных переменных , тем более 32 бита как предлагают Alexey K и ARV не приемлемо, тажкж на счету каждый такт. Т.к. процедура выполняется в прерывании и времяни на выполнение оч.мало

Цитата(arttab @ Apr 24 2013, 04:06) *
а по флагу переполнения не проще ли?

похоже что это самый лаконичный способ!

Код
    if (SREG & (1<<SREG_C))
  80:    0f b6           in    r0, 0x3f; 63
  82:    00 fe           sbrs    r0, 0
  84:    04 c0           rjmp    .+8      ; 0x8e <__vector_9+0x48>

конечно не "brcc m1" ...
Go to the top of the page
 
+Quote Post
maksimp
сообщение Apr 25 2013, 18:09
Сообщение #13


Местный
***

Группа: Участник
Сообщений: 313
Регистрация: 2-07-11
Пользователь №: 66 023



Цитата(MaxiMuz @ Apr 25 2013, 14:05) *
введение дополнительных переменных , тем более 32 бита как предлагают Alexey K и ARV не приемлемо, тажкж на счету каждый такт. Т.к. процедура выполняется в прерывании и времяни на выполнение оч.мало

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

Цитата(MaxiMuz @ Apr 25 2013, 14:05) *
похоже что это самый лаконичный способ!
Код
    if (SREG & (1<<SREG_C))

Он не гаранитированно даёт результат. У вас этот фрагмент кода сейчас такой:
Код
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
if (SREG & (1<<SREG_C))

Допустим что есть ещё некоторые переменные, с которыми до того или после того производятся действия, и фрагмент большего размера может быть например что-то вроде:
Код
uint16_t x,y;
...
x+=y;
...
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
if (SREG & (1<<SREG_C))

Компилятор имеет право переставить действия, и иногда он этим правом пользуется, и может получиться в ассемблере уже что-то будто компилированное с такого текста:
Код
uint16_t x,y;
...
...
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
x+=y;
if (SREG & (1<<SREG_C))

и результат будет неверным.
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Apr 26 2013, 06:06
Сообщение #14


Местный
***

Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658



Цитата(maksimp @ Apr 25 2013, 21:09) *
Проверьте что в ассемблере получится. Может быть соптимизируется и нормально будет, дополнительные переменные могут быть выкинуты компилятором.

Он не гаранитированно даёт результат. У вас этот фрагмент кода сейчас такой:
Код
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
if (SREG & (1<<SREG_C))

Допустим что есть ещё некоторые переменные, с которыми до того или после того производятся действия, и фрагмент большего размера может быть например что-то вроде:
Код
uint16_t x,y;
...
x+=y;
...
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
if (SREG & (1<<SREG_C))

Компилятор имеет право переставить действия, и иногда он этим правом пользуется, и может получиться в ассемблере уже что-то будто компилированное с такого текста:
Код
uint16_t x,y;
...
...
uint16_t temp16;
uint16_t sumADC;
sumADC+=temp16;
x+=y;
if (SREG & (1<<SREG_C))

и результат будет неверным.

я уже пробывал как говорили Они , компил.вводит доп.регистры и код в любом случае получается большой.
А по поводу перестановки действий, вполне возможно ожидать от такого компилятора всяких "пакостей" , поэтому я каждый раз заглдядываю в ассемблерный листинг программы
Go to the top of the page
 
+Quote Post
XVR
сообщение Apr 26 2013, 06:26
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 3 123
Регистрация: 7-04-07
Из: Химки
Пользователь №: 26 847



Сделайте ассемблерную inline функцию. GCC это очень хорошо умеет
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th June 2025 - 00:54
Рейтинг@Mail.ru


Страница сгенерированна за 0.01484 секунд с 7
ELECTRONIX ©2004-2016