Подтвердить что ты не робот

Тернарный (условный) оператор в C

В чем необходимость условного оператора? Функционально он избыточен, поскольку он реализует конструкцию if-else. Если условный оператор более эффективен, чем эквивалентное присваивание if-else, почему не может if-else лучше интерпретироваться компилятором?

4b9b3361

Ответ 1

Тернарный оператор является синтаксическим и читабельным удобством, а не ярлыком производительности. Люди делятся на достоинства этого для условностей разной сложности, но для коротких условий полезно иметь однострочное выражение.

Более того, поскольку это выражение, как Charlie Martin писал, это означает, что оно может появиться в правой части инструкции в C. Это ценно для кратким.

Ответ 2

В C реальная полезность этого заключается в том, что это выражение вместо выражения; то есть вы можете иметь это в правой части (RHS) заявления. Таким образом, вы можете писать некоторые вещи более кратко.

Ответ 3

Некоторые из других ответов даны. Но я удивлен, что никто не упомянул, что его можно использовать для обеспечения правильной корректности const.

Что-то вроде этого:

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

поэтому в основном n является const, начальное значение которого зависит от оператора условия. Самый простой вариант - сделать n не a const, это позволит обычным if инициализировать его. Но если вы хотите, чтобы он был const, это невозможно сделать с помощью обычного if. Лучшей заменой, которую вы могли бы сделать, было бы использовать вспомогательную функцию, подобную этой:

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

const int n = f(x);

но тройная, если версия намного компактнее и, возможно, более читаема.

Ответ 4

Это важно для обфускации кода, например:

Look->       See?!

No
:(
Oh, well
);

Ответ 5

Компактность и возможность встроить конструкцию if-then-else в выражение.

Ответ 6

В C существует много вещей, которые технически не нужны, потому что их можно более или менее легко реализовать с точки зрения других вещей. Вот неполный список:

  • а
  • для
  • Функции
  • Структуры

Представьте себе, как будет выглядеть ваш код без них, и вы можете найти свой ответ. Тернарный оператор является формой "синтаксического сахара", который при использовании с осторожностью и умением облегчает письмо и понимание кода.

Ответ 7

Иногда тройной оператор - лучший способ выполнить работу. В частности, когда вы хотите, чтобы результат тройного значения был l-значением.

Это не очень хороший пример, но я рисую пробел лучше. Одна вещь - certian, это не часто, когда вам действительно нужно использовать тернар, хотя я все еще использую его совсем немного.

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

Одна вещь, о которой я предупреждал бы, хотя и строит тройники вместе. Они становятся реальным проблема во время работы:

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

EDIT: Здесь потенциально лучший пример. Вы можете использовать тернарный оператор для назначения ссылок и значений const, где вам в противном случае нужно было бы написать функцию для ее обработки:

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

const int myValue = getMyValue();

... может стать:

const int myValue = myCondition ? 42 : 314;

Что лучше - спорный вопрос, который я выберу, чтобы не обсуждать.

Ответ 8

Тот факт, что тернарный оператор является выражением, а не выражением, позволяет использовать его в макроразложениях для макросов, подобных функциям, которые используются как часть выражения. Константа, возможно, не была частью оригинального C, но предварительный процессор макроса возвращается назад.

В одном месте, где я видел его, используется массив, в котором используются макросы для доступа с контролируемой границей. Синтаксис для проверяемой ссылки был чем-то вроде aref(arrayname, type, index), где arrayname был фактически указателем на структуру, которая включала границы массива и массив без знака char для данных, тип был фактическим типом данных, а индекс был индекс. Расширение этого было довольно волосатым (и я не собираюсь делать это из памяти), но он использовал некоторые тернарные операторы для проверки привязки.

Вы не можете сделать это как вызов функции в C из-за необходимости полиморфизма возвращаемого объекта. Таким образом, макрос был необходим для выполнения литья типов в выражении. В С++ вы можете сделать это как шаблонный перегруженный вызов функции (вероятно, для оператора []), но C не имеет таких функций.

Изменить: вот пример, о котором я говорил, из массива массивов Berkeley CAD (версия glu 1.4). Документация по использованию array_fetch:

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

Извлечь элемент из массива. ошибка выполнения возникает при попытке ссылки за пределами массив. Нет проверки типов что значение в данной позиции фактически относится к типу, используемому, когда разыменование массива.

и вот макроопределение array_fetch (обратите внимание на использование тернарного оператора и оператора секвенции для выполнения всех подвыражений с правильными значениями в правильном порядке как часть одного выражения):

#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)))

Расширение для array_insert (которое увеличивает массив, если это необходимо, подобно вектору С++) даже более волосатое, включая несколько вложенных тернарных операторов.

Ответ 9

Поскольку никто еще не упомянул об этом, о единственном способе получения умных операторов printf следует использовать тернарный оператор:

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

Предостережение. Существуют некоторые отличия в приоритете оператора при переходе с C на С++ и могут быть удивлены тонкой ошибкой (ошибками), которая возникает из этого.

Ответ 10

Это синтаксический сахар и удобная стенография для коротких блоков if/else, содержащих только один оператор. Функционально обе конструкции должны выполняться одинаково.

Ответ 11

Тернарный оператор может иметь более высокую производительность, чем нормальное, если else, это может иметь решающее значение для встроенных приложений, но оптимизация компилятора может свести эту разницу.

Ответ 12

В некоторых языках программирования if-else является выражением и оценивает значение

def correct = true;
def answer = if (correct) "Yes" else "No";

так что нет необходимости в условном выражении.

Ответ 13

trernary = простая форма if-else. Он доступен в основном для удобства чтения.

Ответ 14

как сказал dwn, производительность была одной из ее преимуществ при росте сложных процессоров, блог MSDN Неклассическое поведение процессора: как что-то может быть быстрее чем не делать это дает пример, в котором четко указано различие между тернарным (условным) оператором и оператором if/else.

введите следующий код:

#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;
}

стоимость для разных границ сильно отличается и более странная (см. исходный материал). а если изменить:

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

к

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

Время выполнения теперь не зависит от граничного значения, так как:

оптимизатор смог удалить ветвь из тернарного выражения.

но на моем рабочем столе Intel i5 cpu/windows 10/vs2015, мой результат теста сильно отличается от блога msdn.

при использовании режима отладки, если /else стоимость:

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

и стоимость тройного оператора:

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 

при использовании режима выпуска, если /else стоимость:

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

и стоимость тройного оператора:

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

тернарный оператор медленнее, чем оператор if else на моей машине!

поэтому в соответствии с различными методами оптимизации компилятора оператор ternal и if/else могут вести себя очень сильно.

Ответ 15

То же, что и

if(0)
do();


if(0)
{
do();
}