简体   繁体   中英

C conditional operator in GCC

From "21st Century C" example 10.8

typedef struct {
double width, height;
} size_s;

size_s width_height(char *papertype){
return
!strcasecmp(papertype, "A4")     ? (size_s) {.width=210, .height=297}
: !strcasecmp(papertype, "Letter") ? (size_s) {.width=216, .height=279}
: !strcasecmp(papertype, "Legal")  ? (size_s) {.width=216, .height=356}
                                 : (size_s) {.width=NAN, .height=NAN};
}

Trying to use this style in WINAVR with GCC

    (a_t_g.value.ax > xx) ? 
    { leds |= rpr;                  //roll positive red 
      leds &= ~rpa;                 //clear amber
     flag |= flagrdd;                   //set the flag for any red
}
: (a_t_g.value.ax < -xx) ?
{ leds  |= rnr;                 //roll negative red
  leds &= ~rna;                 //clear amber
  flag |= flagrdd;                  //set the flag for any red
}
:{}

This results in error: expected expression before '{' token .

Can GCC not handle this or am I doing something wrong? How does one handle the final do nothing in this style?

The ternary ?: operator is for use in expressions. Both branches need to be an expression with a value; it doesn't make sense to have an empty block. Note that using compound blocks in expressions is a GCC extension, one which there's no reason to be using here.

The way to get this to work is to use plain if and else .

if (a_t_g.value.ax > xx) {
    leds |= rpr;                  //roll positive red 
    leds &= ~rpa;                 //clear amber
    flag |= flagrdd;              //set the flag for any red
}
else if (a_t_g.value.ax < -xx) {
    leds  |= rnr;                 //roll negative red
    leds &= ~rna;                 //clear amber
    flag |= flagrdd;              //set the flag for any red
}

?: operator doesn't support blocks which returns nothing, so you have to return something in your code.

(a_t_g.value.ax > xx) ? 
    ({ leds |= rpr;                  //roll positive red 
      leds &= ~rpa;                 //clear amber
     flag |= flagrdd;                   //set the flag for any red
})
: (a_t_g.value.ax < -xx) ?
({ leds  |= rnr;                 //roll negative red
  leds &= ~rna;                 //clear amber
  flag |= flagrdd;                  //set the flag for any red
})
:({})

You can use () around the blocks like I have used in the above code to make this code to work.

The code cited includes this:

return ... ? (size_s) {.width=210, .height=297} ! ...

That is not the "statement expression" GCC extension. It is a C99 designated-initializer, which creates an instance of a size_s with its width and height members initialized to 210 and 297, respectively. (Had there been other members in the struct , they would have been initialized to 0.) The explicit cast (size_s) is required, because it would be impossible to guess the type of the object the initializer is being applied to. That's a perfectly legal syntax which all C99 compilers must recognize.

That's not at all "the same style" as

(a_t_g.value.ax > xx) ? { leds |= rpr; ... } : {}

This is an attempt to use the GCC "statement expression" extension. However, that extension requires that the braced-block be surround with parentheses, so the "correct" way to write it would be:

(a_t_g.value.ax > xx) ? ({ leds |= rpr; ... }) ... : ({});

GCC won't complain about that, although many other compilers would. Unless you know that no-one will ever try compiling your code will with a compiler other than GCC -- which is a dangerous assumption -- you should avoid GCC extensions, particularly in cases like this where the value of the ternary operator is ignored -- making it possible to use ({}) , whose type is void . This code would be more elegant and readable if it were just written in the normal way as an if statement.

Thank you all for the replies. It is now clear to me, and I have learned. After reading the book, I wanted to try something like the example. I then took some if..else working code and substituted the conditional operator. Also I was curious if the else part could be ignored. Apparently not. I was not aware of the GCC extension. The author was quoting C99. Sure, everybody knows the if..else, but on the other hand, the author's code provides a neat table, and is C99 safe. When the use of protothreads limits the use of the switch statement, this would be another tool to use. Knowledge was gained. Thank you

The format of a conditional operator is

condition? value_if_true : value_if_false;

What the original format is, looks like

condition ? value1 : condition2 ? value2 : condition3 ? value3 : last_value;

In your expression, you are missing the :last_value part.

You need to relook at your expression to add this value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM