我已经定义了一个宏,使用我之前问过的问题的输入 here .该宏旨在设置、清除或检查 GPIO 引脚状态。 宏按预期工作,但在编译时出现问题。我在任何使用它的地方都会收到编译器警告:
Warning right-hand operand of comma expression has no effect
当我这样使用宏时:
#define ON 1
#define OFF 2
#define ENA 3
#define OUT_3(x) (x==ON) ? (PORTJ.OUTSET=PIN2_bm) : (x==OFF) ? (PORTJ.OUTCLR=PIN2_bm) : (x==ENA) ? (PORTJ.DIRSET=PIN2_bm) : (PORTJ.DIRCLR=PIN2_bm)
#include <avr/io.h>
if (something) OUT_3(ENA);
但是,如果我这样做:
if (something) {OUT_3(ENA);}
我不再收到警告。
为什么会有差异?我应该如何更改宏以防止出现这种情况?
此外,这会调用警告:
int i=0;
if (something) i=1, OUT_3(ENA);
但是这不会:
int i=0;
if (something) OUT_3(ENA), i=1;
我对逗号分隔表达式的理解显然有点偏差。编译器如何看到这一点?我查看了其他几个与此类似的问题,但仍然没有完全理解其中的区别。
最佳答案
由于以下几个原因,该宏令人讨厌:
- 宏参数应始终用括号括起来,以避免与运算符优先级有关的潜在问题。将
(x==ON)
更改为((x)==ON)
。 - 嵌套的三元运算应该用括号括起来,以使执行顺序明显。更改
a ?乙:丙? d : e
到a ? b : (c ? d : e)
. - 完整的宏应该用括号
#define MACRO (...)
或 do-while-zero loop#define MACRO do {...} while(0)
以避免运算符优先级可能出现的问题。更多内容见下文。 三元运算符在这里并不是很有用,因为您没有使用它的返回值。您应该使用常规的 if 或 switch 语句。这是前面提到的 do-while-zero 循环变得方便的地方:
#define OUT_3(x) \ do { \ if((x) == ON) { PORTJ.OUTSET = PIN2_bm; } \ else if((x) == OFF) { PORTJ.OUTCLR = PIN2_bm; } \ else if((x) == ENA) { PORTJ.DIRSET = PIN2_bm; } \ else { PORTJ.DIRCLR = PIN2_bm; } \ } while(0)
但是宏真的有必要吗?您可以改用内联函数,并摆脱所有宏的怪异之处:
static inline void OUT_3(x_type x) { if(x == ON) { PORTJ.OUTSET = PIN2_bm; } else if(x == OFF) { PORTJ.OUTCLR = PIN2_bm; } else if(x == ENA) { PORTJ.DIRSET = PIN2_bm; } else { PORTJ.DIRCLR = PIN2_bm; } }
通过这些更改,您的错误可能会消失,并且您的代码更易于阅读。
关于C 宏编译器警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55175762/