我已经使用我问过here的上一个问题的输入定义了一个宏。该宏用于设置,清除或检查GPIO引脚状态。 宏可以按预期工作,但是编译时出现问题。在任何使用它的地方都会收到编译器警告:
警告逗号右手操作数无效
当我使用这样的宏时:
#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;
我对用逗号分隔的表达式的理解显然有些偏离。编译器如何看待呢?我看了其他几个与此类似的问题,但仍然不完全了解其中的区别。
答案 0 :(得分:5)
该宏令人讨厌,原因有几个:
(x==ON)
更改为((x)==ON)
。a ? b : c ? d : e
更改为a ? b : (c ? d : e)
。#define MACRO (...)
或零循环do #define MACRO do {...} while(0)
包围,以避免运算符优先级可能出现的问题。下面有更多内容。三元运算符在这里并不是真正有用,因为您没有使用它的返回值。您应该使用常规的if或switch语句。这是前面提到的“做零时循环”变得很方便的地方:
#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; }
}
通过这些更改,您的错误可能会消失,并且您的代码更易于阅读。
答案 1 :(得分:1)
我无法复制您的问题。这段代码可以正常工作
main.cpp
#include <stdio.h>
enum type{ON, OFF, ENA};
#define OUT_3(x) (x==ON) ? (printf("ON\n")) : (x==OFF) ? (printf("OFF\n")) : (x==ENA) ? (printf("ENA\n")) : (printf("OTHER\n"))
int main(){
int a = 2;
if(a == 1) OUT_3(ON);
if(a == 2) OUT_3(OFF);
if(a == 3) OUT_3(ENA);
return 0;
}
编译为
gcc -Wall -O0 -g -o main main.c
您能显示一下ON,OFF,ENA和端口定义的样子吗?