Тернарный (условный) оператор в C - PullRequest
52 голосов
/ 17 апреля 2009

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

Ответы [ 15 ]

154 голосов
/ 17 апреля 2009

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

82 голосов
/ 17 апреля 2009

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

Примерно так:

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

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

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

const int n = f(x);

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

62 голосов
/ 17 апреля 2009

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

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

36 голосов
/ 17 апреля 2009

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

Look->       See?!

No
:(
Oh, well
);
11 голосов
/ 17 апреля 2009

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

10 голосов
/ 17 апреля 2009

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

  1. , а
  2. для
  3. Функции
  4. 1010 * Структура *

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

9 голосов
/ 17 апреля 2009

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

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

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

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

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

РЕДАКТИРОВАТЬ : Вот потенциально лучший пример. Вы можете использовать троичный оператор для назначения ссылок и константных значений, где в противном случае вам нужно было бы написать функцию для его обработки:

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

const int myValue = getMyValue();

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

const int myValue = myCondition ? 42 : 314;

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

8 голосов
/ 02 мая 2009

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

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

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

Edit: Вот пример, о котором я говорил, из пакета Berkeley CAD array (версия 1.4, версия 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 (которое при необходимости увеличивает массив, как вектор C ++) даже более сложное, включая несколько вложенных тернарных операторов.

8 голосов
/ 17 апреля 2009

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

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

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

4 голосов
/ 17 апреля 2009

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

...