4

I have the following code and MPLABX XC8 compiler gives this error:

error: expression is not assignable

U1ERRIRbits.RXFOIF ? uart1.oerr = 1 : uart1.oerr = 0;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^

Here is the relevant code section:

typedef union {
    struct {
        bool ferr  : 1;  // FERIF Framing Error
        bool aerr  : 1;  // ABDOVF Error
        bool oerr  : 1;  // RXFOIF Error
        bool ready : 1;  // Data Ready to be read
        uint8_t reserved : 4;
    };
    uint8_t status;
}uart1_status_t;

static volatile uart1_status_t uart1;

U1ERRIRbits.RXFOIF ? uart1.oerr = 1 : uart1.oerr = 0;

Same thing does not give error when I use

if (U1ERRIRbits.RXFOIF) 
    uart1.oerr = 1;
else 
    uart1.oerr = 0;

Do not understand why?

timrau
  • 22,578
  • 4
  • 51
  • 64
Arda30
  • 107
  • 5
  • 6
    How about `uart1.oerr = U1ERRIRbits.RXFOIF? 1:0;` instead? – Blaze Mar 27 '19 at 12:51
  • 1
    Try instead `U1ERRIRbits.RXFOIF ? uart1.oerr = 1 : (uart1.oerr = 0)`. Condition binds stronger than assignment. [C Operator Precedence](https://en.cppreference.com/w/c/language/operator_precedence). – Scheff's Cat Mar 27 '19 at 12:53
  • @Blaze thank you! It looks way better @ Scheff thank you for the answer! :) – Arda30 Mar 27 '19 at 12:55
  • What does this mean? "Same thing does not give error when I use" This is not the same thing at all! A ternary operator is (as any operator) used as part of an expression. Expressions do not create lvalues. In your alternate version you have separate statements where you assign a value to an lvalue. – Gerhardh Mar 27 '19 at 13:07
  • General rule: A ternary operator is not the same as an `if` clause – Gerhardh Mar 27 '19 at 13:08
  • 1
    Another general rule: avoid using `?:` until it is actually needed. Which isn't very often at all. – Lundin Mar 27 '19 at 14:06

2 Answers2

4
U1ERRIRbits.RXFOIF ? uart1.oerr = 1 : uart1.oerr = 0;

is interpreted as:

(U1ERRIRbits.RXFOIF ? uart1.oerr = 1 : uart1.oerr) = 0;

Which tries to assign 0 to ...? If you want to use such construct, you need braces:

U1ERRIRbits.RXFOIF ? uart1.oerr = 1 : (uart1.oerr = 0);

Or better:

uart1.oerr = U1ERRIRbits.RXFOIF ? 1 : 0;

or:

uart1.oerr = !!U1ERRIRbits.RXFOIF;

or:

uart1.oerr = (bool)U1ERRIRbits.RXFOIF;

or really just:

uart1.oerr = U1ERRIRbits.RXFOIF;

as typeof(uart1.oerr) == bool, the value will be implicitly converted to 1 for nonzero values or 0 for zero.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
2

The answer is simple that, due to C operator precedence,

U1ERRIRbits.RXFOIF ? uart1.oerr = 1 : uart1.oerr = 0;

is compiled as

(U1ERRIRbits.RXFOIF ? uart1.oerr = 1 : uart1.oerr) = 0;

In C, a condition doesn't provide an LValue. Hence, this is a compiler error.

One solution would be to use parentheses:

U1ERRIRbits.RXFOIF ? uart1.oerr = 1 : (uart1.oerr = 0);

Please note, that uart1.oerr = 1 doesn't need parentheses as ? and : act like parentheses (a specialty of the ternary operator).

The even simpler solutions are already mentioned in Kamils answer...

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56