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

Как в Си определить выход за пределы кода (переполнение) результата операции ?

Элементарная ситуация: Имеется два 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

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


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

Такой именно ассемблерный код как вы хотите может быть и не получится.

Варианты:

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)

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


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

Можно попробовать так:

uint16_t temp16;
uint16_t sumADC;

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

Но ассемблерного варианта скорее всего тоже не получится.

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


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

uint16_t temp16;
uint16_t sumADC;
uint32_t sum32;

sum32 = sum32 + temp16;

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

Изменено пользователем Alexey K

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


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

А что, arttab дал плохой совет? Доступ к флагам имеется?

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


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

uint16_t temp16;
uint16_t sumADC;
uint32_t sum32;

sum32 = sum32 + temp16;

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

ну, все-таки скорее всего чуть-чуть иначе:
uint16_t temp16;
uint16_t sumADC;
uint32_t sum32;

sum32 = sum32 + temp16;

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

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


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

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

Иначе крайние варианты не катят

 

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

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


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

uint32_t sum32;

В avr-gcc 4.7.x имеется тип __uint24

 

А что, arttab дал плохой совет? Доступ к флагам имеется?

Имеется. Просто обращение к SREG по маске

if (SREG & (1<<n)) {...}

Лучше всю эту красоту завернуть в макрос типа:

#define add16_sat(a,b) \
do \
{ \
   (a) += (b); \
   if (SREG & (1<<SREG_C)) \
   { \
      (a) = -1U; \
   } \
} while (0)

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


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

Такой именно ассемблерный код как вы хотите может быть и не получится.

Варианты:

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 не приемлемо, тажкж на счету каждый такт. Т.к. процедура выполняется в прерывании и времяни на выполнение оч.мало

 

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

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

 

    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" ...

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


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

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

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

 

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

    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))

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

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


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

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

 

Он не гаранитированно даёт результат. У вас этот фрагмент кода сейчас такой:

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))

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

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

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

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


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

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

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

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

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

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

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

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

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

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