Язык C не имеет логического типа данных, вместо него используются целые числа. Операторы сравнения, такие как == и ‹=, возвращают целочисленное значение 0 для false и 1 для true. Однако оператор if в C считает любое ненулевое значение своего условия эквивалентным истинному. Почему разница? Почему бы не разрешить реляционным операторам возвращать любое ненулевое значение для представления истины?
Возвращаемое значение логического выражения языка C
Ответы (4)
Я считаю, что это было произвольное решение, восходящее к языку-предку C, B.
Цитируя ссылку пользователей на B:
Операторы отношения
<
(меньше чем),<=
(меньше или равно),>
(больше чем) и>=
(больше или равно) принимают целочисленные операнды rvalue. Результат равен единице, если операнды находятся в заданном отношении друг к другу. В противном случае результат равен нулю.
Никакого объяснения этому конкретному выбору не дается, равно как и в Обосновании ANSI C или в 1-м издании книги Кернигана и Ритчи «Язык программирования C» (K&R1) 1978 года.
(Язык-предок B BCPL имел литералы true
и false
, причем true
представлялся со всеми битами, установленными в 1
.)
Язык может быть определен по-другому, и он все равно останется внутренне непротиворечивым. Например, в стандарте могло бы быть сказано, что операторы отношения и равенства дают результат 0
, если условие ложно, или любое произвольное ненулевое значение, если условие истинно. Результат все еще может быть правильно использован в операторе if
или в любом другом контексте, требующем условия. И легко представить ЦП, на котором истинное значение более эффективно представлять как все биты-один, а не как 1
, но стандарт языка не позволяет этого.
Некоторые стандартные библиотечные функции, такие как isdigit()
, могут возвращать любое произвольное ненулевое значение, чтобы указать истинное условие, что еще раз демонстрирует, что это был произвольный выбор. (isdigit
естественно реализуется через поиск по таблице, который может давать значения, отличные от 0
и 1
).
Есть некоторое дополнительное удобство в том, что операторы равенства и отношения дают 0
и 1
. Например, это упрощает подсчет того, сколько условий выполняется:
int count = 0;
count += x == y;
count += foo > bar;
count += this <= that;
Я предполагаю, что было удобно использовать 0
и 1
в первом компиляторе B, поведение было задокументировано и унаследовано до сегодняшнего дня. Изменение определения нарушило бы код, который зависел от предыдущего определения.
И даже если в некоторых системах он относительно неэффективен, это не является большой проблемой. Результат операции равенства или оператора отношения обычно нигде не хранится, поэтому компилятор может представлять результат так, как ему нравится, пока поведение непротиворечиво. В некоторых случаях может потребоваться сгенерировать код для нормализации результата до 0
или 1
, но это вряд ли будет иметь значение.
Если бы условное выражение могло возвращать любое ненулевое значение для true, у вас могли бы возникнуть проблемы при сохранении его в слишком маленькую переменную, в крайнем случае, в однобитовое битовое поле.
struct foo { unsigned int bar: 1; } baz;
baz.bar = 1 == 1;
Если условное выражение 1 == 1
вернет 2 (или любое четное число), у вас будут проблемы, так как baz.bar
в конечном итоге превратится в 0
, что оценивается как false в логическом контексте.
Когда вы используете реляционный оператор внутри условного оператора, компилятор скомпилирует его в оператор "перейти, если больше" или аналогичный оператор и не будет беспокоиться о фактическом вычислении возвращаемого значения выражения <=
. Неважно, что выражение всегда возвращает 0 или 1, потому что это значение фактически никогда не вычисляется.
Единственный случай, когда реляционные операторы, возвращающие 0 или 1, будут иметь значение, — это когда их значение используется в более крупном выражении, таком как арифметика или присваивание переменной. Это гораздо менее распространено, чем ситуация прямого использования их в ветке, и удобство всегда возвращать 1 не очень дорого.
<
не эквивалентно вычитанию. Предположим, x==INT_MAX
и y==INT_MIN
.
- person Keith Thompson; 19.03.2014
В C 0 является ложным, независимо от того, является ли он типом, возвращаемым оператором сравнения, оператором if или чем-то еще, что вы хотите проверить. Однако, несмотря на то, что оператор if() примет за истину все, что не равно нулю, операторы сравнения должны возвращать только один объект, поэтому было решено, что этот объект будет равен '1'. Это разница между тем, возвращаетесь ли вы или принимаете.
Как и в любой другой функции, скажем, int foo(int x){}
вы можете принять любое значение x, но вы должны фактически выбрать, прежде чем выйти из функции, что вы хотите вернуть. Я полагаю, вы могли бы вернуть случайное число, но что хорошего в этом? Вместо этого была выбрана «1».
strcmp()
возвращает любое отрицательное или положительное значение, когда строки разные? :)
- person pmg; 18.03.2014
strcmp()
возвращает отрицательное, 0 или положительное значение. Это не обязательно должна быть разница между чем-либо, хотя иногда это удобный способ реализовать это.
- person Keith Thompson; 18.03.2014
0
и1
, язык допускает сокращенные вычисления:n += (n % 2 == 0); // increment n if it is even
; Кроме того, язык уже принимает любое ненулевое значение для представления true: просто используйте его напрямую в условиях без операторов отношения. - person pmg   schedule 18.03.2014_Bool
/bool
, определенный вstdbool.h
. - person ecatmur   schedule 18.03.2014_Bool
(псевдонимbool
, если у вас есть#include <stdbool.h>
). Он был добавлен стандартом ISO C 1999 года. Но операторы сравнения по-прежнему даютint
результатов. - person Keith Thompson   schedule 18.03.2014