【问题标题】:C: A cure for the warning: integer overflow in expression?C:警告的治疗方法:表达式中的整数溢出?
【发布时间】:2010-02-27 15:31:29
【问题描述】:

我正在尝试组织我的 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 它就像一个魅力)

有没有办法将该常量类型转换为整数以使编译器满意?

非常感谢, 哈姆扎。

【问题讨论】:

  • 这个平台上的sizeof(int)是什么?
  • U1BRG 的类型是什么(以及该类型的大小)?
  • 为什么你认为BRGVAL变成了25.0416667?宏中表达式中的所有组件都是整数,因此当宏被替换时,表达式将使用整数算术进行评估。编译器警告的问题是溢出,而不是浮点截断。
  • U!1BRG 是无符号整数(16 位),它是 MPLAB C30 编译器

标签: c embedded


【解决方案1】:

整数溢出意味着您已超出 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

【讨论】:

  • 嗨 Phillip,感谢您的建议,以下代码现在似乎对我有用 #define FOSC 8000000L #define BAUDRATE 9600L #define BRGVAL (FOSC/2)/(16*BAUDRATE)- 1 出于某种奇怪的原因,如果我将 (int) 强制类型添加到 BRGVAL,我会得到一个 65536 的值(int 的限制?),不知道为什么会发生这种情况。没有演员表,它似乎可以工作......
  • @Adam BAUDRATE 必须很长,或者幻数 16 必须很长,否则 16*BAUDRATE 会溢出。
  • @Hamza 你用什么代码来添加演员?所有括号对于演员表都是必需的。如果您正在执行 (int)(FOSC/2)/(16*BAUDRATE)-1 或 (int)BRGVAL,那么您不是将整个表达式转换为而是仅将 (FOSC/2) 转换为 int,这将溢出并成为一些小数目。然后将这个小数除以 (16*BAUDRATE),一个大数,结果为 0。然后减去 1,得到 -1。将 -1 分配给无符号整数,然后环绕并得到 65535。简而言之,如果进行强制转换,请在要强制转换的整个表达式周围添加括号。
  • 这很愚蠢:我把括号放在了正确的位置,但编译器似乎与以前的构建文件混淆了,一个简单的 make clean 和重新编译修复了它。非常感谢您的帮助和清晰的解释...
  • 是的,当然。 +1 为您提供详尽的解释,我希望我能给您另一个 +1 以启用编译器警告!
【解决方案2】:

我喜欢菲利普的回答,但我认为更好的解决方案是减少公式并将宏更改为:

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

这样做,您消除了强制转换,因此如果您选择的低波特率会导致分频器值对于 16 位 int 来说太大,编译器可以继续警告您。

【讨论】:

    【解决方案3】:

    我可能会使用这个:

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

    【讨论】:

      【解决方案4】:

      从您的示例中不清楚 U1BRG 是全局变量还是 #define'ed 常量。在任何情况下,只需转换为整数即可:

       U1BRG = (int)BRGVAL;
      

      【讨论】:

      • 你好 Js,U1BRG 在另一个 heaser 文件中被定义为一个无符号整数,我尝试进行 (int) 强制转换,但仍然弹出相同的错误
      【解决方案5】:

      您没有指出这一点,U1BRG 的数据类型是什么?如果是int,如图所示进行投射

      #define FOSC 8000000 #define 波特率 9600 #define BRGVAL ((long)(FOSC/2)/(16*BAUDRATE)-1) 无效的UART_init(){ U1BRG = BRGVAL; }

      编辑: 考虑到 Adam Liss 的评论,即 unsigned int 太小而无法保存宏,我已将其更改为 long...感谢 Adam 的提醒...

      希望这会有所帮助, 最好的祝福, 汤姆。

      【讨论】:

      • 你好汤姆,它是'unsigned int'类型,我试过做一个(int)强制转换,但仍然弹出同样的错误......
      • FOSC/2 仍然太大而无法放入 int。
      • 你仍然会溢出 16*BAUDRATE,它不适合 int。
      猜你喜欢
      • 1970-01-01
      • 2016-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-07
      • 2010-09-08
      • 2021-02-14
      相关资源
      最近更新 更多