C宏编译器警告

时间:2019-03-15 04:53:48

标签: c avr avr-gcc

我已经使用我问过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;

我对用逗号分隔的表达式的理解显然有些偏离。编译器如何看待呢?我看了其他几个与此类似的问题,但仍然不完全了解其中的区别。

2 个答案:

答案 0 :(得分:5)

该宏令人讨厌,原因有几个:

  1. 宏参数应始终用括号括起来,以避免运算符优先级的潜在问题。将(x==ON)更改为((x)==ON)
  2. 嵌套三元运算应使用括号括起来,以使执行顺序显而易见。将a ? b : c ? d : e更改为a ? b : (c ? d : e)
  3. 完整的宏应该用括号#define MACRO (...)或零循环do #define MACRO do {...} while(0)包围,以避免运算符优先级可能出现的问题。下面有更多内容。
  4. 三元运算符在这里并不是真正有用,因为您没有使用它的返回值。您应该使用常规的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)
    
  5. 但是宏是否真的必要?您可以改用内联函数,并消除所有宏怪异之处:

    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和端口定义的样子吗?