web-dev-qa-db-fra.com

Les nombres négatifs renvoient-ils faux en C / C ++?

Lors de l'évaluation d'entiers en tant que booléens en C/C++, les nombres négatifs sont-ils vrais ou faux? Sont-ils toujours vrais/faux quels que soient les compilateurs?

47
Jason Maldonado

Toutes les valeurs non nulles seront converties en true et les valeurs nulles en false. Les nombres négatifs étant différents de zéro, ils sont convertis en true.

Citant de la norme C++ 11 (soulignement le mien):

4.12 Conversions booléennes [conv.bool]

1 Une valeur de type arithmétique, énumération non étendue, pointeur ou pointeur sur le type de membre peut être convertie en valeur de type bool. ne valeur nulle, une valeur de pointeur nulle ou une valeur de pointeur de membre nul est convertie en false; toute autre valeur est convertie en true. Une valeur de type std :: nullptr_t peut être converti en une valeur de type bool; la valeur résultante est fausse.


Sont-ils toujours vrais/faux quels que soient les compilateurs?

Vous n'obtiendrez la garantie ci-dessus que lorsque votre compilateur est conforme aux normes, ou du moins, est conforme à cette partie spécifique de la norme. En pratique, tous les compilateurs ont ce comportement standard, donc il n'y a pas grand-chose à craindre.

60
Mark Garcia

Vous pouvez le tester vous-même en compilant ceci:

#include <stdio.h>

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

Résultats:

$ gcc -Wall -pedantic test.c -o test-c
$ g ++ -Wall -pedantic test.c -o test-cpp
$ ./test-c
- 1 est vrai
$ ./test-cpp
- 1 est vrai

Bien sûr, pour répondre à la deuxième partie de votre question, "Sont-ils toujours vrais/faux quels que soient les compilateurs?", La seule façon d'être complètement sûr est de regarder la spécification. En général cependant, les compilateurs vous avertiront si vous faites quelque chose de dangereux, et vous pouvez voir dans la sortie ci-dessus que même avec "pedantic" avertissements , gcc considère que ce code est parfaitement bien.

7
Brendan Long

Réponse courte: les valeurs négatives, et toutes les valeurs non nulles en général, sont traitées comme vraies lorsqu'elles sont utilisées comme conditions.

Pour C, il existe un certain nombre de contextes dans lesquels une expression est traitée comme une condition. Les conditions ne sont pas nécessairement de type bool ou _Bool; ce type n'a été ajouté à la langue que par la norme de 1999.

Le plus évident de ces contextes est l'expression dans une instruction if, mais il existe d'autres exemples: while, do-while, La deuxième expression dans une for en-tête, le premier opérande de l'opérateur conditionnel ?: et le ou les opérandes des opérateurs !, && et ||. (Je pense que c'est une liste exhaustive, mais je ne suis pas certain.)

Voici ce que la norme C dit sur le comportement de l'instruction if (les "deux formes" font référence à if avec et sans clause else):

Dans les deux formes, la première sous-instruction est exécutée si l'expression est différente de 0.

Ce qui signifie que ceci:

if (foo) ...

est équivalent à ceci:

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

(ajout de parenthèses supplémentaires pour éviter tout problème de priorité des opérateurs). La signification est claire si foo est de type int. Si foo est d'un type à virgule flottante, 0 Est converti dans le même type (ce qui peut entraîner des subtilités si la valeur se trouve être un zéro négatif ou un NaN). Et si foo est un pointeur, 0 Est traité comme une constante de pointeur nulle; if (ptr) est équivalent à if (ptr != NULL) (en supposant que la définition de NULL est visible).

Pour C++, les règles sont énoncées un peu différemment, mais l'effet est le même. La condition dans une instruction C++ if est convertie en type bool (contrairement à C, le type bool est intégré à C++ depuis ses débuts). La conversion d'une valeur de n'importe quel type scalaire en bool est définie par la norme C++ comme:

Une valeur nulle, une valeur de pointeur nulle ou une valeur de pointeur de membre nul est convertie en faux; toute autre valeur est convertie en true. Une valeur de type std :: nullptr_t peut être convertie en une valeur de type bool; la valeur résultante est false.

Ainsi, en C et C++, toute valeur scalaire (c'est-à-dire entier, virgule flottante ou pointeur) peut être utilisée comme condition, et la condition est fausse si le scalaire est égal à zéro et vraie si elle n'est pas égale à zéro . C définit cela comme une comparaison d'inégalité à 0; C++ le définit comme une conversion en bool - mais le résultat est le même.

Cela écarte un peu le sujet de la question, mais je mentionnerai qu'il est important de noter qu'une valeur qui est traitée comme une vraie condition n'est pas nécessairement égale à true. true (qui est 1 en C si vous avez #include <stdbool.h>, et une valeur unique de type bool en C++) n'est qu'une des nombreuses valeurs qui possèdent "véracité" lorsqu'il est utilisé dans un état. C'est pourquoi vous ne devriez presque jamais écrire:

if (cond == true) ...

en C ou C++ (sauf si vous avez vraiment besoin de le comparer à cette seule valeur); Ecrivez:

if (cond) ...

Un exemple 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";
}

La sortie est:

n has truthiness
n != true
5
Keith Thompson

Tout ce qui n'est pas 0 sera converti en true ( 1 dans le cas de C) une valeur de zero sera convertie en false (0 dans le cas de C). En ce qui concerne [~ # ~] c [~ # ~] si nous regardons le projet de norme C99 section 6.3.1.2 Type booléen paragraphe 1 dit:

Lorsqu'une valeur scalaire est convertie en _Bool, le résultat est 0 si la valeur se compare à 0; sinon, le résultat est 1.

Par souci d'exhaustivité si nous regardons la section 7.16 Type et valeurs booléennes paragraphe 2 dit:

The macro 

 bool

expands to _Bool.

par rapport à C++ le projet de norme C++ dans la section 4.12 Conversions booléennes paragraphe 1 dit ( le mien est souligné):

Une valeur de type arithmétique, énumération non étendue, pointeur ou pointeur sur le type de membre peut être convertie en valeur de type bool. Une valeur nulle, une valeur de pointeur nulle ou une valeur de pointeur de membre nul est convertie en faux; toute autre valeur est convertie en vrai. [...]

Cela devrait être valable quel que soit le compilateur que vous utilisez.

3
Shafik Yaghmour