预处理器:在令牌之前缺少二元运算符

时间:2016-06-14 13:58:48

标签: c c-preprocessor avr-gcc

我试图在XMEGA微控制器中设置USART模块,并偶然发现我找不到的错误。为清楚起见,我给你完整的代码。因此,此头文件中没有任何内容丢失。 (F_CPU在主文件中定义)

#ifndef USART_H_
#define USART_H_

#include <avr/io.h>



#define USART_BAUDRATE          4800
#define USART_BSCALE            -3

#if USART_BSCALE < 0
    #define USART_BSEL          F_CPU / (pow(2,USART_BSCALE) * 16 * USART_BAUDRATE) - 1
    #define USART_BAUD_REAL     F_CPU / (pow(2,USART_BSCALE) * 16 * (USART_BSEL + 1))
#else
    #define USART_BSEL          (1 / (pow(2,USART_BSCALE))) * (F_CPU / (16 * USART_BAUDRATE) - 1)
    #define USART_BAUD_REAL     F_CPU / (16 * ((pow(2,USART_BSCALE) * USART_BSEL) + 1))
#endif

#define USART_BAUD_ERROR        USART_BAUD_REAL * 1000 / USART_BAUDRATE

#if USART_BAUD_ERROR<990 || USART_BAUD_ERROR>1010    /* <-- ERROR IS IN THIS LINE! */
    #error Baud rate error too high!
#endif


#endif /* USART_H_ */

编译器以错误

结束
missing binary operator before token "("

在标记的行中。之前有过括号,但我删除了它们,尝试了不同的括号组合,但编译器仍然在那里看到它们。这有什么不对?

2 个答案:

答案 0 :(得分:2)

在预处理阶段评估#if预处理器指令。函数pow在运行时进行评估。因此,您无法在传递给#if的预处理器令牌(宏)中使用它。您需要在编译时计算所有这些值。

提示:“2次n”与1 << n(按位左移)相同。

此外,还有一些其他严重问题:

  • 您已标记此AVR,因此您可能不应使用浮点数。它们不仅会使您的程序变得非常缓慢并且可以用于各种错误的可能性,使用它们也没有任何好处。

    如果运气好的话,您会收到“丢失浮点库”或类似信息的警告。如果你运气不好,该程序将链接并吹走你的所有执行速度和内存。

    在考虑使用浮点之前,检查目标系统是否有FPU可能是明智的。

  • 您需要正确编写宏,并在宏表达式周围加上括号。就像您正确编写的第二个USART_BSEL一样。否则,如果在表达式中使用宏,则可能会出现与运算符优先级相关的非常微妙且非常严重的错误。每一篇不错的C书都在预处理器章节中解决了这个问题。

答案 1 :(得分:0)

如果希望预处理器对表达式求值,则它必须是常量。 pow()是运行时函数,编译器无法在编译时对其进行评估。

在宏主体周围使用括号,否则会遇到问题。

观察数字常量的类型。根据类型评估操作。 1/ANY_NUMBER给出0,因为除法是在带符号的int中执行的。

#define USART_BAUDRATE       4800U
#define USART_BSCALE         (-3)

#if USART_BSCALE < 0
  #define USART_BSEL          (F_CPU*(1UL<<(-USART_BSCALE)) / (16U*USART_BAUDRATE) - 1U)
  #define USART_BAUD_REAL     (F_CPU*(1UL<<(-USART_BSCALE)) / (16U*(USART_BSEL+1U)) )
#else
  #define USART_BSEL          (F_CPU / ((1UL<<USART_BSCALE)*(16U*USART_BAUDRATE-1U)) )
  #define USART_BAUD_REAL     (F_CPU / (16U*((1UL<<USART_BSCALE)*USART_BSEL+1U) )
#endif

#define USART_BAUD_ERROR      ( USART_BAUD_REAL * 1000U / USART_BAUDRATE )

建议:使用四舍五入技巧可以提高除法的准确性:

#define USART_BSEL_DIVISOR  ((1UL<<USART_BSCALE)*(16U*USART_BAUDRATE-1U))
#define USART_BSEL          ( (F_CPU+USART_BSEL_DIVISOR/2) / USART_BSEL_DIVISOR )