Возвращаемое значение логического выражения языка C

Язык C не имеет логического типа данных, вместо него используются целые числа. Операторы сравнения, такие как == и ‹=, возвращают целочисленное значение 0 для false и 1 для true. Однако оператор if в C считает любое ненулевое значение своего условия эквивалентным истинному. Почему разница? Почему бы не разрешить реляционным операторам возвращать любое ненулевое значение для представления истины?


person user3277859    schedule 18.03.2014    source источник
comment
Благодаря тому, что реляционные операторы возвращают 0 и 1, язык допускает сокращенные вычисления: n += (n % 2 == 0); // increment n if it is even; Кроме того, язык уже принимает любое ненулевое значение для представления true: просто используйте его напрямую в условиях без операторов отношения.   -  person pmg    schedule 18.03.2014
comment
вернуть любое ненулевое значение, чтобы представить истину - что можно получить, оставив его неоднозначным? Дает ли это больше гибкости разработчикам? Как они могли извлечь выгоду из этой гибкости?   -  person Brian Cain    schedule 18.03.2014
comment
Последние 15 лет в языке C используется логический тип данных: _Bool/bool, определенный в stdbool.h.   -  person ecatmur    schedule 18.03.2014
comment
C имеет логический тип. Он называется _Bool (псевдоним bool, если у вас есть #include <stdbool.h>). Он был добавлен стандартом ISO C 1999 года. Но операторы сравнения по-прежнему дают int результатов.   -  person Keith Thompson    schedule 18.03.2014
comment
В первую очередь на основе мнений, особенно просмотр обсуждения в комментариях к различным постам.   -  person rici    schedule 19.03.2014


Ответы (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, но это вряд ли будет иметь значение.

person Keith Thompson    schedule 18.03.2014

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

struct foo { unsigned int bar: 1; } baz;
baz.bar = 1 == 1;

Если условное выражение 1 == 1 вернет 2 (или любое четное число), у вас будут проблемы, так как baz.bar в конечном итоге превратится в 0, что оценивается как false в логическом контексте.

person SzG    schedule 18.03.2014

Когда вы используете реляционный оператор внутри условного оператора, компилятор скомпилирует его в оператор "перейти, если больше" или аналогичный оператор и не будет беспокоиться о фактическом вычислении возвращаемого значения выражения <=. Неважно, что выражение всегда возвращает 0 или 1, потому что это значение фактически никогда не вычисляется.

Единственный случай, когда реляционные операторы, возвращающие 0 или 1, будут иметь значение, — это когда их значение используется в более крупном выражении, таком как арифметика или присваивание переменной. Это гораздо менее распространено, чем ситуация прямого использования их в ветке, и удобство всегда возвращать 1 не очень дорого.

person hugomg    schedule 18.03.2014
comment
< не эквивалентно вычитанию. Предположим, x==INT_MAX и y==INT_MIN. - person Keith Thompson; 19.03.2014
comment
@KeithThompson: Это хороший момент. Я зашел слишком далеко с аналогией SUB = CMP. - person hugomg; 19.03.2014

В C 0 является ложным, независимо от того, является ли он типом, возвращаемым оператором сравнения, оператором if или чем-то еще, что вы хотите проверить. Однако, несмотря на то, что оператор if() примет за истину все, что не равно нулю, операторы сравнения должны возвращать только один объект, поэтому было решено, что этот объект будет равен '1'. Это разница между тем, возвращаетесь ли вы или принимаете.

Как и в любой другой функции, скажем, int foo(int x){} вы можете принять любое значение x, но вы должны фактически выбрать, прежде чем выйти из функции, что вы хотите вернуть. Я полагаю, вы могли бы вернуть случайное число, но что хорошего в этом? Вместо этого была выбрана «1».

person ciphermagi    schedule 18.03.2014
comment
О... и почему strcmp() возвращает любое отрицательное или положительное значение, когда строки разные? :) - person pmg; 18.03.2014
comment
Я почти уверен, что он просто возвращает разницу между str1 и str2, но не на 100% положительно. - person ciphermagi; 18.03.2014
comment
@KeithThompson Это не тот вопрос, который был задан. - person ciphermagi; 18.03.2014
comment
@ciphermagi: стандарт C говорит только о том, что strcmp() возвращает отрицательное, 0 или положительное значение. Это не обязательно должна быть разница между чем-либо, хотя иногда это удобный способ реализовать это. - person Keith Thompson; 18.03.2014
comment
@KeithThompson Прекратите намеренно неверно истолковывать вещи. - person ciphermagi; 18.03.2014
comment
@ciphermagi: я полагаю, что это именно тот вопрос, который был задан: почему бы не разрешить операторам отношения возвращать любое ненулевое значение для представления истины? - person Keith Thompson; 18.03.2014
comment
@KeithThompson И я ответил на этот вопрос: поскольку нужно было выбрать значение, поэтому они выбрали значение. - person ciphermagi; 18.03.2014
comment
Любая неверная интерпретация с моей стороны совершенно непреднамеренна. Будьте осторожны с обвинениями. Значение должно быть выбрано либо стандартом языка, либо отдельным компилятором. Вопрос, на мой взгляд, в том, почему язык не оставил решение на усмотрение каждого компилятора, как мог бы. - person Keith Thompson; 19.03.2014
comment
Весь смысл того, что я сказал, заключается в том, что сама функция не может просто произвольно решить какое-то число. Программист должен был выбрать во время создания библиотеки, которая реализовывала операторы сравнения, какое-то осмысленное возвращаемое значение. Конечно, он мог бы заставить его возвращать случайное значение между 1 и двоичным пределом возвращаемого типа переменной, но какой от этого толк? - person ciphermagi; 19.03.2014
comment
давайте продолжим это обсуждение в чате - person Keith Thompson; 19.03.2014