【问题标题】:Preprocessor: missing binary operator before token预处理器:令牌前缺少二元运算符
【发布时间】:2016-06-14 13:58:47
【问题描述】:

我正在尝试在 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_ */

编译器以错误结束

在标记“(”之前缺少二元运算符

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

【问题讨论】:

  • 您不能在#if 预处理器指令参数中使用 C 函数 (pow...),因为它是在编译时由预处理器评估的...
  • 哦,那很糟糕。那么还有其他方法可以计算幂吗?
  • 二的幂?移位(支持:gcc.gnu.org/onlinedocs/gcc-3.0.2/cpp_4.html#SEC38
  • 并且您应该重新考虑您的计算以获得仅整数的中间结果(是的,这是可能的)。它不会像现在这样工作。
  • 除此之外:将(brackets) 放在所有宏操作数周围。否则以-1结尾的那个可能会在后面的宏中被错误地使用。这不是 C 优先规则:它是文本替换。

标签: c c-preprocessor avr-gcc


【解决方案1】:

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

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

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

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

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

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

  • 您需要正确编写宏,并用括号括住宏表达式。就像你的第二个USART_BSEL 写得正确。否则,如果您的宏在表达式中使用,您可能会遇到与运算符优先级相关的非常微妙和非常严重的错误。每本不错的 C 书籍都在预处理器章节中解决了这个问题。

【讨论】:

    【解决方案2】:

    如果你想让预处理器计算一个表达式,它必须是常量。 pow() 是一个运行时函数,它不能在编译时被预处理器求值。

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

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

    #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 )
    

    【讨论】:

      猜你喜欢
      • 2018-09-01
      • 2017-06-27
      • 1970-01-01
      • 2014-02-15
      • 1970-01-01
      • 2022-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多