AVR C hex и dec умножение не так, как ожидалось - PullRequest
0 голосов
/ 09 мая 2018

Я только что обнаружил ошибку в своем коде при умножении шестнадцатеричных чисел (например, 0xFFFF) на целые числа dec (например, 2). Это код, где возникает проблема:

print_int_new_line(0xFFFF*2);
print_int_new_line(65535*2);

Выполнение этого кода дает мне следующий результат:

65534
131070

Это соответствующий код UART:

void print_int_new_line(uint64_t data) {
    print_int(data);

    print_new_line();
}

void print_int(uint64_t data) {
    char data_buffer[(int)(log(data)+2)]; // size of the number (log(number)+1) + 1 for the /0

    ultoa(data, data_buffer, 10); // convert the int to string, base 10

    // print the newly created string
    print_string(data_buffer);
}

void print_string(char * data) {

    // transmit the data char by char
    for(; *data != '\0'; data++){
        USART_transmit(data);
    }
}

void USART_transmit(const char * data){
    /* Wait for empty transmit buffer */
    while ( !( UCSR0A & (1<<UDRE0)) )
    ;

    /* Put data into buffer, sends the data */
    UDR0 = *data;
}

Некоторая информация о моей настройке:

MCU: ATmega2560 Плата: Arduino Mega2560 Скорость UART: 38400 IDE: Atmel Studio 7.0.4.1417

Использование AVR toolchain.

Я прочитал на этой странице stackoverflow, что возможно умножение между шестнадцатеричным и десятичным числом. Кроме того, проверка этого в онлайн c компиляторе дает правильный вывод.

Может кто-нибудь дать мне объяснение?

1 Ответ

0 голосов
/ 09 мая 2018

Такое поведение обусловлено различиями в обработке десятичных и шестнадцатеричных целочисленных констант.

Для 0xFFFF и 65535 компилятор сначала попытается преобразовать значение в int. Но поскольку платформа имеет 16-битный тип int, где INT_MAX равен 32767, это преобразование не может быть выполнено.

Ключевым отличием является следующий шаг. Для шестнадцатеричной константы 0xFFFF компилятор попытается преобразовать ее в unsigned int, что эквивалентно (unsigned int)65535. Но для десятичных констант преобразования в беззнаковые типы не предпринимаются. Следующая попытка преобразования в long int. Это успешно и эквивалентно (long int)65535.

Так что звонки на print_int_new_line эквивалентны:

print_int_new_line((unsigned int)65535*2);
print_int_new_line((long int)65535*2);

И когда 2 повышают до умножения:

print_int_new_line((unsigned int)65535*(unsigned int)2);
print_int_new_line((long int)65535*(long int)2);

Результат unsigned int первого умножения слишком мал для хранения полного результата, поэтому он усекается до 65534. long int может содержать результат, поэтому он дает правильный ответ 131070.

Вы можете заставить шестнадцатеричную константу использовать long int, добавив L (т.е. 0xFFFFL).

...