C: лекарство от предупреждения: целочисленное переполнение в выражении? - PullRequest
9 голосов
/ 27 февраля 2010

Я пытаюсь упорядочить свою библиотеку UART и немного ее откорректировать, добавив несколько #define, чтобы потом можно было настроить ее, не углубляясь в код, но, похоже, я не могу получить следующий бит рабочий код:

#define FOSC        8000000
#define BAUDRATE    9600
#define BRGVAL      (FOSC/2)/(16*BAUDRATE)-1

void uart_init(){
   U1BRG = BRGVAL;
}

После того, как вычисление BRGVAL становится 25.0416667, и, поскольку оно не является целым числом, я получаю следующее предупреждение, когда назначаю его в U1BRG:

UART.c: в функции 'uart_init':

UART.c: 24: предупреждение: целочисленное переполнение в выражении

... и код просто не работает на целевом оборудовании. (Если я вручную введу U1BRG = 25, он будет работать как шарм)

Есть ли способ преобразовать эту константу в целое число, чтобы компилятор был доволен?

Большое спасибо, Хамза.

Ответы [ 5 ]

24 голосов
/ 27 февраля 2010

Целочисленное переполнение означает, что вы превысили верхний предел значения int, который, вероятно, будет 32767, если вы получаете эту ошибку. Это не имеет ничего общего с плавающей точкой; указанные вами операции на самом деле являются целочисленными математическими операциями, поэтому дробная часть деления в любом случае отбрасывается.

Попробуйте что-то вроде этого:

#define FOSC        8000000L
#define BAUDRATE    9600L
#define BRGVAL      ((unsigned int)((FOSC/2)/(16*BAUDRATE)-1))

void uart_init(){
   U1BRG = BRGVAL;
}

Суффикс L превращает эти константы в тип long вместо типа int. Приведение (unsigned int) преобразуется в тип U1BRG и позволяет компилятору понять, что вы понимаете, что значение long будет помещаться в unsigned int, и, таким образом, скрывать любые предупреждения, которые оно может выдать вам.

Обычно замалчивать предупреждения компилятора - это плохая практика, но в этом случае ясно, что, хотя вам необходимо long для хранения промежуточных значений в вычислениях, конечный результат будет помещаться в unsigned int.

8 голосов
/ 27 февраля 2010

Мне нравится ответ Филиппа, но я думаю, что лучшее решение - это уменьшить формулу и изменить свой макрос на:

#define BRGVAL (FOSC/32/BAUDRATE-1)

При этом вы исключаете приведение, чтобы компилятор продолжал предупреждать вас, если вы выберете низкую скорость передачи, что приведет к слишком большому значению делителя для 16-разрядного целого.

0 голосов
/ 27 февраля 2010

Вы не смогли указать на это. Какой тип данных для U1BRG? Если это int, разыграйте его, как показано

#define FOSC        8000000
#define BAUDRATE    9600
#define BRGVAL      ((long)(FOSC/2)/(16*BAUDRATE)-1)

void uart_init(){
   U1BRG = BRGVAL;
}

Редактировать: Исправлено это, чтобы учесть комментарий Адама Лисса , что беззнаковое целое слишком мало, чтобы содержать результат макроса Я изменил его, чтобы сделать его long ... Спасибо Адаму за хэдсэп ...

Надеюсь, это поможет, С наилучшими пожеланиями, Том.

0 голосов
/ 27 февраля 2010

Из вашего примера не ясно, является ли U1BRG глобальной переменной или константой # define'ed. В любом случае, просто приведение к целому числу должно работать:

 U1BRG = (int)BRGVAL;
0 голосов
/ 27 февраля 2010

Я бы, наверное, использовал это:

#define BRGVAL      ((int)(FOSC/2)/(16*BAUDRATE)-1)
...