ternary operator virginity

Go To Last Post
17 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Why is this failing to compile?

 

(nr_entries1 > nr_entries2) ? nr_entries = nr_entries1 : nr_entries = nr_entries2;

 

This topic has a solution.
Last Edited: Sun. Jul 14, 2019 - 06:05 PM
This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The ternary operator is used to select between values, not select between statements. What you want is this:

nr_entries = nr_entries1 > nr_entries2 ? nr_entries1 : nr_entries2;

Or better yet use a type appropriate max() function to improve readability.

github.com/apcountryman/build-avr-gcc: a script for building avr-gcc

github.com/apcountryman/toolchain-avr-gcc: a CMake toolchain for cross compiling for the Atmel AVR family of microcontrollers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi

 

apcountryman wrote:
The ternary operator is used to select between values, not select between statements.

 

That's not always true. The ternary operator can be used to select an expression containing an assignment, since assignments return values:

a>b ? (c=a) : (c=b);

Moreover, depending on the compiler's version and options, the following expressions can generate an error, just generate a warning or be accepted by the compiler:

a>b ? c=a : c=b;
(a>b ? a : b) = c;

For instance, avr-gcc version 4.8 used in older Arduino toolchains accepts both expressions.

Last Edited: Sun. Jul 14, 2019 - 06:51 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think it's more a C vs C++ thing rather than compiler versions or options.

In C you would need parnetheses to write it as  a > b ? (c = a) : (c = b)

but don't do it that way!

Do what the solution in #2 says.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:
I think it's more a C vs C++ thing rather than compiler versions or options.
It's a version issue since different versions of the same compilers accept or refuse the syntax.

 

For instance, the last expression generates a warning with the message "this will be a hard error in the future" in GCC version 4.2. It is not accepted anymore in the lastest version of GCC.

 

MrKendo wrote:
Do what the solution in #2 says.
Of course that's the best solution, because the code is more readable. But one must keep in mind that the ternary operator can also contain assignments.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

_pepe_ wrote:
It's a version issue since different versions of the same compilers accept or refuse the syntax.

For instance, the last expression generates a warning with the message "this will be a hard error in the future" in GCC version 4.2. It is not accepted anymore in the lastest version of GCC.

Ok, fair enough.

I was thinking the OP's case (without adding parentheses around the assignments) is simply invalid in the C language (essentially down to operator precedence), but it might be valid in C++.

 

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks guys, always wondered why use the ternary operator instead of a if/else.

But for simple compares its neater.

 

Wm.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

Fianawarrior wrote:

Thanks guys, always wondered why use the ternary operator instead of a if/else.

But for simple compares its neater.

 

Wm.

 

You can initialize a const variable with a ternary but not if/else:

int const foo = bar >= baz ? bar : baz;

A nice thing to note about ternaries  is that you can chain them (but make sure you structure them to maintain readability):

int const foo = bar > baz ? bar
              : baz > qux ? baz
                          : qux;

 

github.com/apcountryman/build-avr-gcc: a script for building avr-gcc

github.com/apcountryman/toolchain-avr-gcc: a CMake toolchain for cross compiling for the Atmel AVR family of microcontrollers

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fianawarrior wrote:
Thanks guys, always wondered why use the ternary operator instead of a if/else.
I like it for things like:

printf("valve = %s", valvevar ? "open" : "closed");

As apcountryman says you can even stack them:

printf("state = %s", (statevar == IDLE) ? "IDLE" : (statevar == WAITING) ? "WAITING : "ACTIVE"));

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Fianawarrior wrote:
always wondered why use the ternary operator instead of a if/else.
Because the ternary operator is consistent with a value, and the if/else statement is not.

 

A ternary operator's expression can always be used as a r-value, and sometimes as a l-value, depending on the compiler -- see above.

 

As a r-value, it can save the use of a temporary variable.

 

For instance, these codes are equivalent:

 

if( whatToTest() ? testThis() : testThat() ){
  // long block of code
  ...
}
int tmp;
if( whatToTest() )
  tmp = testThis();
else
  tmp = testThat():
if( tmp ){
  // long block of code
  ...
}
if( whatToTest() ){
  if( testThis() ){
    // long block of code
    ...
  } else
  if( testThat() ){
    // same long block of code
    ...
  }
}

In your opinion, which one is the smallest and the most readable ?

 

Last Edited: Mon. Jul 15, 2019 - 08:36 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

_pepe_ wrote:

In your opinion, which one is the smallest and the most readable ?

The 3rd one doesn't have the same functionality as the first two, but I get the point you're making.

Avoiding use of a temporary variable should not be an issue with modern compiler, I would expect to end up with the same compiled code either way.

I might be inclined to write it as

bool result = what_to_test() ? test_this() : test_that();
if (result)
{
    /* block of code */
}

The main point with ternary operator is that it is an operator, so can be used inside expressions in places where you can't use if/else, sometimes this is convenient, but you can always write the code in some way to achieve the same thing without ternary, and I would expect the resulting compiled code to be (pretty much) the same either way. So focus on what you think is the most readable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:
I might be inclined to write it as
+1

 

That's exactly what I was going to suggest. It avoids an overly complex compound statement, gives easy access to the returned state and the compiler was going to have an "internal" temp result anyway so it likely does not generate any more code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I use the ternary when it appears neater in the source. Nice looking source code runs better.

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

MrKendo wrote:

_pepe_ wrote:

In your opinion, which one is the smallest and the most readable ?

The 3rd one doesn't have the same functionality as the first two, ...

It does, since the second "long block code" is the same as the first one.

 

If whatToTest() is true then testThis() is tested else testThat() is tested. If the test is true, then the "long block code" is executed.

 

MrKendo wrote:
Avoiding use of a temporary variable should not be an issue with modern compiler, I would expect to end up with the same compiled code either way.
Of course, this is not an issue for a modern compiler when the optimization is on, but we agreed that the point was the readability of the source code. But, precisely:
- the more elements it contains, the higher the risk of making mistakes

- the longer it is, the smaller portion of the program is shown on the screen at the same time

- the less it corresponds to the generated program [e.g. optimizable temporary variables], the less the debug mode operations correspond to the final program execution.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:

the compiler was going to have an "internal" temp result anyway

In this case, the compiler may replace the temporary variable with jumps, without the use of a unique internal result.

Last Edited: Mon. Jul 15, 2019 - 02:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

_pepe_ wrote:

MrKendo wrote:

 

 

_pepe_ wrote:

 

In your opinion, which one is the smallest and the most readable ?

 

 

The 3rd one doesn't have the same functionality as the first two, ...

It does, since the second "long block code" is the same as the first one.

Yes but the logic is different. The first 2 cases call testThat when whatToTest is false.

The 3rd case call testThat when whatToTest is true but testThis is false.

That's a good example of why the 3rd way is probably the worst way to write it.

 

For what it's worth, the following 3 versions all compile to exactly the same code (using -Os, avr-gcc (GCC) 4.9.2)

int main(void)
{
#if 1
    // v1
    bool has_foo = PINB ? PINC : PIND;
    if (has_foo)
    {
        PORTB = 0xa5;
    }
#endif

#if 0
    // v2
    if (PINB ? PINC : PIND)
    {
        PORTB = 0xa5;
    }
#endif

#if 0
    // v3
    if (PINB)
    {
        if (PINC)
        {
            PORTB = 0xa5;
        }
    }
    else
    {
        if (PIND)
        {
            PORTB = 0xa5;
        }
    }
#endif

    return 0;
}

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Amazing comments about the Ternary Operator.  Thanks guys, I will be using it more often.

 

Slán