[ACCEPTED]-The ternary (conditional) operator in C-conditional-operator

Accepted answer
Score: 160

In C, the real utility of it is that it's 4 an expression instead of a statement; that is, you 3 can have it on the right-hand side (RHS) of 2 a statement. So you can write certain things 1 more concisely.

Score: 86

Some of the other answers given are great. But 12 I am surprised that no one mentioned that 11 it can be used to help enforce const correctness 10 in a compact way.

Something like this:

const int n = (x != 0) ? 10 : 20;

so 9 basically n is a const whose initial value is 8 dependent on a condition statement. The 7 easiest alternative is to make n not a const, this 6 would allow an ordinary if to initialize it. But 5 if you want it to be const, it cannot be done 4 with an ordinary if. The best substitute you 3 could make would be to use a helper function 2 like this:

int f(int x) {
    if(x != 0) { return 10; } else { return 20; }
}

const int n = f(x);

but the ternary if version is 1 far more compact and arguably more readable.

Score: 69

The ternary operator is a syntactic and 8 readability convenience, not a performance 7 shortcut. People are split on the merits 6 of it for conditionals of varying complexity, but 5 for short conditions, it can be useful to 4 have a one-line expression.

Moreover, since 3 it's an expression, as Charlie Martin wrote, that means it can 2 appear on the right-hand side of a statement 1 in C. This is valuable for being concise.

Score: 43

It's crucial for code obfuscation, like 1 this:

Look->       See?!

No
:(
Oh, well
);
Score: 13

Compactness and the ability to inline an 1 if-then-else construct into an expression.

Score: 11

There are a lot of things in C that aren't 8 technically needed because they can be more 7 or less easily implemented in terms of other 6 things. Here is an incomplete list:

  1. while
  2. for
  3. functions
  4. structs

Imagine 5 what your code would look like without these 4 and you may find your answer. The ternary 3 operator is a form of "syntactic sugar" that 2 if used with care and skill makes writing 1 and understanding code easier.

Score: 9

Sometimes the ternary operator is the best 16 way to get the job done. In particular 15 when you want the result of the ternary 14 to be an l-value.

This is not a good example, but 13 I'm drawing a blank on somethign better. One 12 thing is certian, it is not often when you 11 really need to use the ternary, although 10 I still use it quite a bit.

const char* appTitle  = amDebugging ? "DEBUG App 1.0" : "App v 1.0";

One thing I would 9 warn against though is stringing ternaries 8 together. They become a real
problem at 7 maintennance time:

int myVal = aIsTrue ? aVal : bIsTrue ? bVal : cIsTrue ? cVal : dVal;

EDIT: Here's a potentially 6 better example. You can use the ternary 5 operator to assign references & const 4 values where you would otherwise need to 3 write a function to handle it:

int getMyValue()
{
  if( myCondition )
    return 42;
  else
    return 314;
}

const int myValue = getMyValue();

...could become:

const int myValue = myCondition ? 42 : 314;

Which 2 is better is a debatable question that I 1 will choose not to debate.

Score: 8

Since no one has mentioned this yet, about 5 the only way to get smart printf statements is 4 to use the ternary operator:

printf("%d item%s", count, count > 1 ? "s\n" : "\n");

Caveat: There 3 are some differences in operator precedence 2 when you move from C to C++ and may be surprised 1 by the subtle bug(s) that arise thereof.

Score: 8

The fact that the ternary operator is an 41 expression, not a statement, allows it to 40 be used in macro expansions for function-like 39 macros that are used as part of an expression. Const 38 may not have been part of original C, but 37 the macro pre-processor goes way back.

One 36 place where I've seen it used is in an array 35 package that used macros for bound-checked 34 array accesses. The syntax for a checked 33 reference was something like aref(arrayname, type, index), where arrayname 32 was actually a pointer to a struct that 31 included the array bounds and an unsigned 30 char array for the data, type was the actual 29 type of the data, and index was the index. The 28 expansion of this was quite hairy (and I'm 27 not going to do it from memory), but it 26 used some ternary operators to do the bound 25 checking.

You can't do this as a function 24 call in C because of the need for polymorphism 23 of the returned object. So a macro was 22 needed to do the type casting in the expression. In 21 C++ you could do this as a templated overloaded 20 function call (probably for operator[]), but 19 C doesn't have such features.

Edit: Here's 18 the example I was talking about, from the 17 Berkeley CAD array package (glu 1.4 edition). The 16 documentation of the array_fetch usage is:

type
array_fetch(type, array, position)
typeof type;
array_t *array;
int position;

Fetch 15 an element from an array. A runtime error 14 occurs on an attempt to reference outside 13 the bounds of the array. There is no 12 type-checking that the value at the given 11 position is actually of the type used 10 when dereferencing the array.

and here 9 is the macro defintion of array_fetch (note 8 the use of the ternary operator and the 7 comma sequencing operator to execute all 6 the subexpressions with the right values 5 in the right order as part of a single expression):

#define array_fetch(type, a, i)         \
(array_global_index = (i),              \
  (array_global_index >= (a)->num) ? array_abort((a),1) : 0,\
  *((type *) ((a)->space + array_global_index * (a)->obj_size)))

The 4 expansion for array_insert ( which grows 3 the array if necessary, like a C++ vector) is 2 even hairier, involving multiple nested 1 ternary operators.

Score: 4

It's syntatic sugar and a handy shorthand 3 for brief if/else blocks that only contain 2 one statement. Functionally, both constructs 1 should perform identically.

Score: 1

like dwn said, Performance was one of its 18 benefits during the rise of complex processors, MSDN 17 blog Non-classical processor behavior: How doing something can be faster than not doing it gives an example which clearly says 16 the difference between ternary (conditional) operator 15 and if/else statement.

give the following 14 code:

#include <windows.h>
#include <stdlib.h>
#include <stdlib.h>
#include <stdio.h>

int array[10000];

int countthem(int boundary)
{
 int count = 0;
 for (int i = 0; i < 10000; i++) {
  if (array[i] < boundary) count++;
 }
 return count;
}

int __cdecl wmain(int, wchar_t **)
{
 for (int i = 0; i < 10000; i++) array[i] = rand() % 10;

 for (int boundary = 0; boundary <= 10; boundary++) {
  LARGE_INTEGER liStart, liEnd;
  QueryPerformanceCounter(&liStart);

  int count = 0;
  for (int iterations = 0; iterations < 100; iterations++) {
   count += countthem(boundary);
  }

  QueryPerformanceCounter(&liEnd);
  printf("count=%7d, time = %I64d\n",
         count, liEnd.QuadPart - liStart.QuadPart);
 }
 return 0;
}

the cost for different boundary are 13 much different and wierd (see the original 12 material). while if change:

 if (array[i] < boundary) count++;

to

 count += (array[i] < boundary) ? 1 : 0;

The execution 11 time is now independent of the boundary 10 value, since:

the optimizer was able to remove 9 the branch from the ternary expression.

but 8 on my desktop intel i5 cpu/windows 10/vs2015, my 7 test result is quite different with msdn 6 blog.

when using debug mode, if/else cost:

count=      0, time = 6434
count= 100000, time = 7652
count= 200800, time = 10124
count= 300200, time = 12820
count= 403100, time = 15566
count= 497400, time = 16911
count= 602900, time = 15999
count= 700700, time = 12997
count= 797500, time = 11465
count= 902500, time = 7619
count=1000000, time = 6429

and ternary operator 5 cost:

count=      0, time = 7045
count= 100000, time = 10194
count= 200800, time = 12080
count= 300200, time = 15007
count= 403100, time = 18519
count= 497400, time = 20957
count= 602900, time = 17851
count= 700700, time = 14593
count= 797500, time = 12390
count= 902500, time = 9283
count=1000000, time = 7020 

when using release mode, if/else cost:

count=      0, time = 7
count= 100000, time = 9
count= 200800, time = 9
count= 300200, time = 9
count= 403100, time = 9
count= 497400, time = 8
count= 602900, time = 7
count= 700700, time = 7
count= 797500, time = 10
count= 902500, time = 7
count=1000000, time = 7

and ternary operator 4 cost:

count=      0, time = 16
count= 100000, time = 17
count= 200800, time = 18
count= 300200, time = 16
count= 403100, time = 22
count= 497400, time = 16
count= 602900, time = 16
count= 700700, time = 15
count= 797500, time = 15
count= 902500, time = 16
count=1000000, time = 16

the ternary operator is slower than 3 if/else statement on my machine!

so according 2 to different compiler optimization techniques, ternal 1 operator and if/else may behaves much different.

Score: 1
  • Some of the more obscure operators in C 38 exist solely because they allow implementation 37 of various function-like macros as a single 36 expression that returns a result. I would 35 say that this is the main purpose why the 34 ?: and , operators are allowed to exist, even 33 though their functionality is otherwise 32 redundant.

    Lets say we wish to implement 31 a function-like macro that returns the largest 30 of two parameters. It would then be called 29 as for example:

    int x = LARGEST(1,2);
    

    The only way to implement 28 this as a function-like macro would be

    #define LARGEST(x,y) ((x) > (y) ? (x) : (y))
    

    It 27 wouldn't be possible with an if ... else statement, since 26 it does not return a result value. Note)

  • The 25 other purpose of ?: is that it in some cases 24 actually increases readability. Most often 23 if...else is more readable, but not always. Take 22 for example long, repetitive switch statements:

    switch(something)
    {
      case A: 
        if(x == A)
        {
          array[i] = x;
        }
        else
        {
          array[i] = y;
        }
        break;
    
      case B: 
        if(x == B)
        {
          array[i] = x;
        }
        else
        {
          array[i] = y;
        }
        break;
      ...
    }
    

    This 21 can be replaced with the far more readable

    switch(something)
    {
      case A: array[i] = (x == A) ? x : y; break;
      case B: array[i] = (x == B) ? x : y; break;
      ...
    }
    
  • Please 20 note that ?: does never result in faster code than 19 if-else. That's some strange myth created by confused 18 beginners. In case of optimized code, ?: gives 17 identical performance as if-else in the vast majority 16 of the cases.

    If anything, ?: can be slower than 15 if-else, because it comes with mandatory implicit 14 type promotions, even of the operand which 13 is not going to be used. But ?: can never 12 be faster than if-else.


Note) Now of course someone will 11 argue and wonder why not use a function. Indeed 10 if you can use a function, it is always preferable 9 over a function-like macro. But sometimes 8 you can't use functions. Suppose for example 7 that x in the example above is declared at 6 file scope. The initializer must then be 5 a constant expression, so it cannot contain 4 a function call. Other practical examples 3 of where you have to use function-like macros 2 involve type safe programming with _Generic or "X 1 macros".

Score: 0

ternary = simple form of if-else. It is 1 available mostly for readability.

More Related questions