Preprocessor: missing binary operator before token

喜欢而已 提交于 2020-01-07 00:35:10

问题


I'm trying to set up the USART module in an XMEGA micro controller and stumble over an error I can not find. For clarity I give you the complete code. So nothing in this header file is missing. (F_CPU is defined in the main file)

#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_ */

The compiler ends with the error

missing binary operator before token "("

in the marked line. There have been brackets before, but I removed them, tried different bracket combinations but the compiler still does see them there. What is wrong here?


回答1:


The #if pre-processor directive is evaluated during the pre-processing stages. The function pow is evaluated in run-time. Therefore you can't use it inside pre-processor tokens (macros) that are passed to #if. You'll want to compute all these values at compile-time.

Hint: "2 times n" is the same as 1 << n (bit-wise left shift).

In addition, there are some other serious issues:

  • You have tagged this AVR so you probably shouldn't use floating point numbers. They will not only make your program incredibly slow and open up for all kinds of bug possibilities, there is nothing gained from using them.

    If you are lucky, you would get warnings for "missing floating point library" or similar. If you are unlucky, the program will link and blow away all your execution speed and memory.

    It might be wise to check if your target system even has a FPU before considering using floating point.

  • You need to write macros proper, with parenthesis surrounding the macro expression. Just like your second USART_BSEL which is properly written. Otherwise if your macro is used in an expression, you can get very subtle and very severe bugs related to operator precedence. Every half-decent C book addresses this very issue in the pre-processor chapter.



回答2:


If you want preprocessor to evaluate an expression, it has to be constant. pow() is a runtime function, it can't be evaluated by the preprocessor at compile time.

Use parentheses around macro bodies, otherwise you'll run into problems.

Watch the type of the number constants. The operations are evaluated according to the types. 1/ANY_NUMBER gives 0, because the division is performed in signed 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 )

Suggestion: you can achieve better accuracy for divisions with the rounding trick:

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


来源:https://stackoverflow.com/questions/37814166/preprocessor-missing-binary-operator-before-token

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!