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

Не отрицательные числа возвращают false в C/С++?

При оценке целых чисел как булевых в C/С++ отрицательные числа истинны или ложны? Всегда ли они истинны/ложны независимо от компиляторов?

4b9b3361

Ответ 1

Все ненулевые значения будут преобразованы в true и нулевые значения до false. При отрицательных числах, отличных от нуля, они преобразуются в true.

Цитата из стандарта С++ 11 (акцент мой):

4.12 Логические преобразования [conv.bool]

1 Значение арифметики, неперечисленное перечисление, указатель или указатель тип члена может быть преобразован в prvalue типа bool. Ноль значение, значение нулевого указателя или значение указателя нулевого элемента преобразуется до false; любое другое значение преобразуется в true.. Значение типа std:: nullptr_t может быть преобразован в prvalue типа bool; итоговое значение false.


Всегда ли они истинны/ложны независимо от компиляторов?

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

Ответ 2

Вы можете проверить это самостоятельно, скомпилировав это:

#include <stdio.h>

int main(int argc, char** argv) {
    if (-1) {
        printf("-1 is true\n");
    } else {
        printf("-1 is false\n");
    }
    return 0;
}

Результаты:

$ gcc -Wall -pedantic test.c -o test-c
$ g++ -Wall -pedantic test.c -o test-cpp
$./test-c
-1 is true
$./test-cpp
-1 is true

Конечно, чтобы ответить на вторую часть вашего вопроса: "Всегда ли они верны/неверны независимо от компиляторов?", Единственный способ быть полностью уверенным - взглянуть на спецификацию. В целом, однако, компиляторы предупреждают вас, если вы делаете что-то опасное, и вы можете видеть из вышеприведенного вывода, что даже с "педантичными" предупреждениями, gcc считает этот код идеальным.

Ответ 3

Краткий ответ. Отрицательные значения и любые ненулевые значения в целом рассматриваются как истинные при использовании в качестве условий.

Для C существует ряд контекстов, в которых выражение рассматривается как условие. Условия не обязательно относятся к типу bool или _Bool; этот тип был добавлен к языку только по стандарту 1999 года.

Наиболее очевидным из этих контекстов является выражение в выражении if, но есть и другие примеры: while, do-while, второе выражение в заголовке for, первый операнд условного оператора ?: и операнд операторов !, && и ||. (Я думаю, что это исчерпывающий список, но я не уверен.)

Вот что говорит стандарт C о поведении оператора if ("две формы" относятся к if с предложением else и без него):

В обеих формах первая подстановка выполняется, если выражение не равно 0.

Что означает, что это:

if (foo) ...

эквивалентно этому:

if ((foo) != 0) ...

(добавление дополнительных скобок, чтобы избежать проблем с приоритетом операторов). Смысл понятен, если foo имеет тип int. Если foo имеет некоторый тип с плавающей точкой, 0 преобразуется в тот же тип (что может вызвать некоторые тонкости, если значение оказывается отрицательным нулем или NaN). И если foo является указателем, 0 обрабатывается как константа нулевого указателя; if (ptr) эквивалентен if (ptr != NULL) (при условии, что определение NULL является видимым).

Для C++ правила сформулированы немного по-другому, но эффект тот же. Условие в операторе C++ if преобразуется в тип bool (в отличие от C, тип bool был встроен в C++ с момента его ранней истории). Преобразование значения любого скалярного типа в bool определяется стандартом C++ как:

Нулевое значение, нулевое значение указателя или нулевое значение указателя элемента преобразовано в ложное; любое другое значение преобразуется в true. prvalue типа std::nullptr_t может быть преобразовано в prvalue из введите bool; результирующее значение ложно.

Таким образом, как в C, так и в C++ любое скалярное значение (т.е. целое число, число с плавающей запятой или указатель) может использоваться как условие, и условие ложно, если скаляр равен нулю, и истинно, если оно не равно в ноль. C определяет это как сравнение неравенства с 0; C++ определяет его как преобразование в bool - но результат тот же.

Это немного выходит за рамки вопроса, но я упомяну, что важно отметить, что значение, которое рассматривается как истинное условие, не обязательно равно true. true (то есть 1 в C, если у вас есть #include <stdbool.h> и уникальное значение типа bool в C++) - это лишь одно из многих значений, которые обладают "истинностью" при использовании в условии. Вот почему вы почти никогда не должны писать:

if (cond == true) ...

либо в C, либо в C++ (если вам действительно не нужно сравнивать его с этим одним значением); просто напишите:

if (cond) ...

Пример C++:

#include <iostream>
int main() {
    int n = 2;
    if (n)         std::cout << "n has truthiness\n";
    else           std::cout << "n does not have truthiness\n";
    if (n == true) std::cout << "n == true\n";
    else           std::cout << "n != true\n";
}

Вывод:

n has truthiness
n != true

Ответ 4

Все, что не является 0, будет преобразовано в true (1 в случае C). Значение zero будет преобразовано в false (0 в случае C). Что касается C, если мы посмотрим на черновик проекта C99 6.3.1.2 Логический тип параграфа 1 гласит:

Когда любое скалярное значение преобразуется в _Bool, результат равен 0, если значение сравнивается с равным до 0; в противном случае результат равен 1.

Для полноты, если мы посмотрим на раздел 7.16 Логический тип и значения, приведенные в параграфе 2, говорят:

The macro 

 bool

expands to _Bool.

относительно С++ черновик стандарта С++ в разделе 4.12 Логические преобразования в абзаце 1 говорят (выделено мной):

Значение арифметики, неперечисленное перечисление, указатель или указатель на тип члена может быть преобразовано в prvalue типа bool. Нулевое значение, значение нулевого указателя или значение указателя нулевого элемента преобразуется в значение false; любое другое значение преобразуется в значение true. [...]

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

Ответ 5

Хороший вопрос. Ответ "зависит".
if (-1) { // this is always true
}

С другой стороны, предположим, что вы на 16-битной машине:

if (-65536) { // this is always false
}

С другой стороны,

int a = whatever doesn't matter;
if (a < 0) { // this might or might not be true
    if (a) { // this will always be true if we get here
    }
}

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