NULL
est-il assimilé à une valeur fausse ?!
sur un nombre négatif ?a[i] = i++
?i++
vaut i
?i++ * i++
?&&
et ||
?Oui, il existe un type booléen en C. C'est un ajout de la dernière
version de la norme (C99). Il s'agit du type _Bool
défini dans <stdbool.h>
. Cet en-tête contient
également les définitions de true
et false
.
Une macro bool
est souvent définie comme équivalent à
_Bool
.
Rappelons également qu'en C, une valeur est « fausse » si elle est
nulle (ou équivalent), et « vraie » sinon. Les définitions de
true
et false
suivent cette règle. Ainsi, la
valeur entière de true
est 1
et celle de
false
est 0
.
NULL
est-il assimilé à une valeur fausse ?Oui, la valeur NULL
est apparentée à un 0
.
Les écritures if(p != NULL)
et if(p)
sont donc équivalentes. De même, if(p == NULL)
est
équivalent à if(!p)
.
Voir aussi les questions 10.1 et 7.5.
!
sur un nombre négatif ?L'opérateur !
sur un nombre négatif donne bien ce que l'on
attend, à savoir 0
.
Voir aussi la question 10.1.
a[i] = i++
?Ce genre d'expression fait partie des « undefined
behaviour », ou comportement indéfini. Cela signifie que le
résultat d'une telle opération dépend du compilateur.
L'opérateur ++
modifie la valeur de i
, alors que
celle-ci est utilisée ailleurs dans l'expression.
C'est ce que l'on appelle un « effet de bords ».
i++
vaut i
?Effectivement, i++
vaut i
, avant
l'incrémentation. Toutefois, rien ne dit dans quel sens est
calculée l'expression a[i] = i++
.
Est-ce le i++
qui est évalué avant le a[i]
, ou
le contraire ? On n'en sait rien, c'est pourquoi l'on dit que c'est un
comportement indéfini.
i++ * i++
?Oui. La norme ne précise pas pour les opérateurs binaires dans quel ordre les opérandes sont évalués.
Pas en général. Les parenthèses ne donnent qu'un ordre partiel d'évaluation, entre les opérateurs. Voici un petit exemple :
a = f() + g() * h(); b = (f() + g()) * h();
Les parenthèses dans la deuxième expression modifient l'ordre d'évaluation de l'addition et de la multiplication. Par contre, l'ordre dans lequel seront évaluées les fonctions est indéfini, dans l'une ou l'autre des deux expressions. Cela ne dépend que du compilateur.
Pour forcer un ordre d'évaluation, il faut utiliser une écriture séquentielle, avec des variables temporaires.
tf = f(); tg = g(); th = h(); b = (tf + tg) * th;
On a alors un comportement parfaitement défini sur toutes les cibles, quel que soit le compilateur.
&&
et ||
?Ces deux opérateurs forment une exception à la règle. La norme prévoit que les opérandes de ces deux opérateurs soient évalués de gauche à droite. De plus, l'évaluation s'arrête dès que le résultat est connu.
Le principe est simple. Si les variables sont de types différents, il y aura un cast implicite vers le type le plus précis. On parle de promotion. Voici les règles de base :
long double
, l'autre
est converti en un long double
.double
,
l'autre est converti en un double
.float
,
l'autre est converti en un float
.char
et
short
sont convertis en int
.long
, l'autre
est converti en un long
.En C99, il faut rajouter le type long long
.
Cela se complique dans le cas d'opérandes unsigned
.
Les comparaisons entre valeurs signées et non signées dépendent de
la machine et de la taille des différents types.
lvalue est un terme qui est utilisé pour définir les expressions que l'on peut mettre à gauche d'une affection. Toute variable modifiable est une lvalue.
Quand le compilateur prévient que le membre gauche d'une affectation n'est pas une lvalue, c'est souvent parce que l'on ne voulait pas faire une affectation, mais une comparaison (cf. 15.5).