C 宏编译器警告

标签 c avr avr-gcc

我已经定义了一个宏,使用我之前问过的问题的输入 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;

我对逗号分隔表达式的理解显然有点偏差。编译器如何看到这一点?我查看了其他几个与此类似的问题,但仍然没有完全理解其中的区别。

最佳答案

由于以下几个原因,该宏令人讨厌:

  1. 宏参数应始终用括号括起来,以避免与运算符优先级有关的潜在问题。将 (x==ON) 更改为 ((x)==ON)
  2. 嵌套的三元运算应该用括号括起来,以使执行顺序明显。更改 a ?乙:丙? d : ea ? b : (c ? d : e).
  3. 完整的宏应该用括号 #define MACRO (...) 或 do-while-zero loop #define MACRO do {...} while(0) 以避免运算符优先级可能出现的问题。更多内容见下文。
  4. 三元运算符在这里并不是很有用,因为您没有使用它的返回值。您应该使用常规的 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)
    
  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; }
    }
    

通过这些更改,您的错误可能会消失,并且您的代码更易于阅读。

关于C 宏编译器警告,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55175762/

相关文章:

c - 初始化元素不是常量,试图定义变量的默认值 - C

c - AVR 8 位,关于 SFR 位访问的 C 标准合规性

c - 如果宏未定义,如何闪烁错误?

c - 将所有文件包含在一个 .h 文件中并在 AVR 的任何位置都包含该文件是否是一种好习惯?

c - 它正在录制,但录制的视频无法播放。它给出错误 "moov data not found",请帮我解决这个问题

c++ - 套接字接收错误数据

c - 如何在Arduino中获取全局变量的flash地址

c - AVR LCD错误: lcd. h:没有这样的文件或目录

c - AVR EEPROM读写

c - 从 C 中的输入文件逐个读取字符?