Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет norvog ([info]norvog)
@ 2010-10-28 01:10:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Программизма псот
Обнаружил забавный баг.


unsigned int m;
unsigned int m_old;

void main( void)
{
// Test values
m = 6;
m_old = 5;

if ( ( (m - m_old) >= 20) ||
( (m_old - m) >= 20))
{
LED = 1;
}




По задумке в коде проверяется отклонение значения некоторого параметра ( m) от его предыдущего значения ( m_old). Т.е. берем модуль разности и сравниваем с некоторым порогом ( 20). Если модуль больше порога - выполняем некоторые действия. В примере ниже - зажигаем светодиод.
А баг собственно в том, что 100 - 101 = -1. Т.е. 0xFFFF. Т.е. в данном варианте одно из условий всегда выполняется...



А теперь о том как это решается приведением типов:



signed int i, j, a, b;
unsigned int k, l;
char bool1, bool2, bool3, bool4, bool5, bool6;

unsigned int m;
unsigned int m_old;

void main( void)
{
// Test values
m = 6;
m_old = 5;

if ( ( ( signed int)(m - m_old) >= 20) ||
( ( signed int)(m_old - m) >= 20))
{
LED = 1;
}

i = m - m_old;
j = m_old - m;
k = ( unsigned int) m - m_old;
l = ( unsigned int) m_old - m;
a = ( signed int) m - m_old;
b = ( signed int) m_old - m;

bool1 = ( (m - m_old) >= 20);
bool2 = ( (m_old - m) >= 20);
bool3 = ( ( unsigned int) (m - m_old) >= 20);
bool4 = ( ( unsigned int) (m_old - m) >= 20);
bool5 = ( ( signed int) (m - m_old) >= 20);
bool6 = ( ( signed int) (m_old - m) >= 20);



И watch table




Address Symbol Name Value Hex Decimal Binary Char

080 i 0x0001 0x0001 1 00000000 00000001 '..'
082 j 0xFFFF 0xFFFF -1 11111111 11111111 '..'
088 k 0x0001 0x0001 1 00000000 00000001 '..'
08A l 0xFFFF 0xFFFF 65535 11111111 11111111 '..'
084 a 0x0001 0x0001 1 00000000 00000001 '..'
086 b 0xFFFF 0xFFFF -1 11111111 11111111 '..'
08C bool1 0x00 0x00 0 00000000 '.'
08D bool2 0x01 0x01 1 00000001 '.'
08E bool3 0x00 0x00 0 00000000 '.'
08F bool4 0x01 0x01 1 00000001 '.'
090 bool5 0x00 0x00 0 00000000 '.'
091 bool6 0x00 0x00 0 00000000 '.'





(Добавить комментарий)


[info]kouzdra
2010-10-28 04:19 (ссылка)
А где баг? Вроде все правильно.

(Ответить) (Ветвь дискуссии)


[info]norvog
2010-10-28 22:19 (ссылка)
Дабы уточнить: код на С под микроконтроллеры микрочип. Компилятор Микрочиповский C18, контроллер семейства pic18.

А баг в том, что в изначальном варианте ( m_old - m) беззнаковое. Разность равна "-1", т.е. 0xFFFF, что сильно больше значения с которым сравниваем.

Смотрим выражение "( m_old - m) >= 20"
Получается, что ( 6 - 5) = -1, а записывается "-1" как 0xFFFF, так как тип у нас беззнаковый, то 0xFFFF это не "-1", а 65525, что >= 20.

По уму надо было приводить тип разности к знаковому и потом уже сравнивать с константой:
( signed int)( m_old - m) >= 20.
Тогда ( m_old - m) равнялось бы именно "-1"

А самое грустное, что это выражение встречается страницы после 40-ой кода, а переменные инициализированы где-то в самом начале. Т.е. заметить что с типом что-то не то довольно сложно. Чисто случайно эту багу выловил, потому как код не мой и все вызывает сомнения, т.ч. увидев подозрительный способ взятия модуля - решил проверить...

(Ответить) (Уровень выше)