C macro compiler warnings

hvg*_*guy 0 c avr avr-gcc

I've defined a macro, using input from a previous question I asked here. The macro is intended to either set, clear, or check a GPIO pins state. The macro works as expected however a problem shows up when compiling. I get compiler warnings anywhere it's used:

Warning right-hand operand of comma expression has no effect

when I use the macro like this:

#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);
Run Code Online (Sandbox Code Playgroud)

However, if I do this:

if (something) {OUT_3(ENA);}
Run Code Online (Sandbox Code Playgroud)

I no longer get the warnings.

Why is there a difference? How should I alter the macro to prevent this scenario?

Additionally this invokes the warning:

int i=0;
if (something) i=1, OUT_3(ENA);
Run Code Online (Sandbox Code Playgroud)

However this does not:

int i=0;
if (something) OUT_3(ENA), i=1;
Run Code Online (Sandbox Code Playgroud)

My understanding of comma separated expressions is clearly a bit off. How is the compiler seeing this? I looked at several other questions similar to this but still do not fully understand the difference.

use*_*733 5

该宏令人讨厌,原因如下:

  1. 宏参数应始终用括号括起来,以避免潜在的运算符优先级问题。更改(x==ON)((x)==ON)
  2. 嵌套三元运算应使用括号括起来,以使执行顺序显而易见。更改a ? b : c ? d : ea ? b : (c ? d : e)
  3. 完整的宏应该用括号#define MACRO (...)或“零时执行”循环包围,#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)
    
    Run Code Online (Sandbox Code Playgroud)
  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; }
    }
    
    Run Code Online (Sandbox Code Playgroud)

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