Reputation: 41
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);
However, if I do this:
if (something) {OUT_3(ENA);}
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);
However this does not:
int i=0;
if (something) OUT_3(ENA), i=1;
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.
Upvotes: 0
Views: 302
Reputation: 16043
That macro is nasty for several reasons:
(x==ON)
to ((x)==ON)
.a ? b : c ? d : e
to a ? b : (c ? d : e)
.#define MACRO (...)
or do-while-zero loop #define MACRO do {...} while(0)
to avoid possible problems with operator precedence. More below.Ternary operator is not really useful here as you are not using it's return value. You should rather use regular if or switch statements. This is where previously mentioned do-while-zero loop becomes handy:
#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)
But is macro really even necessary? You could use inline function instead, and get rid of all macro weirdness:
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; }
}
With these changes, your error will likely go away, and your code is much easier to read.
Upvotes: 5
Reputation: 989
I can't reproduce your issue. This code works without any problem
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;
}
Compiled with
gcc -Wall -O0 -g -o main main.c
Could you please show how the definitions of ON, OFF, ENA and the Port definitions look like?
Upvotes: 1