opérateur booléen ++ et -

104

Aujourd'hui, en écrivant du code Visual C ++, je suis tombé sur quelque chose qui m'a surpris. Il semble que C ++ supporte ++ (incrémentation) pour bool, mais pas - (décrément). Est-ce juste une décision aléatoire, ou il y a une raison à cela?

Cela compile:

static HMODULE hMod = NULL;
static bool once = false;
if (!once++)
    hMod = LoadLibrary("xxx");

Cela ne:

static HMODULE hMod = NULL;
static bool once = true;
if (once--)
    hMod = LoadLibrary("xxx");
Suma
la source
2
hm, idem pour xcode et gcc compiler
Vladimir
Oui, ++onceet once++travaillez avec gcc, mais pas les décrémentations.
Justin Ardini
Peut-être retaguer «histoire» au lieu de «mot-clé opérateur», donc ceci est regroupé avec toutes les autres explications amusantes quant à pourquoi diverses choses folles sont raisonnables si vous considérez l'historique? :)
Jon Hanna
Notez que depuis C ++ 17, l'opérateur de pré-incrémentation pour boolest obsolète, souce .
cogle
cela peut être remplacé par std::exchange(once,false)(note: pas atomique), si vous voulez quelque chose de non obsolète.
golvok du

Réponses:

90

Cela vient de l'histoire de l'utilisation de valeurs entières comme booléens.

Si xest un int, mais je l'utilise comme un booléen, if(x)...alors l'incrémentation signifiera que quelle que soit sa valeur de vérité avant l'opération, elle aura une valeur de vérité d' trueaprès elle (sauf dépassement de capacité).

Cependant, il est impossible de prédire le résultat d' --une connaissance donnée uniquement de la valeur de vérité de x, car cela pourrait entraîner false(si la valeur intégrale est 1) ou true(si la valeur intégrale est autre chose - notamment cela inclut 0 [ false] et 2 ou plus [true ]).

Donc, en tant que raccourci ++, a travaillé, et --n'a pas fait.

++ est autorisé sur les booléens pour des raisons de compatibilité avec cela, mais son utilisation est déconseillée dans la norme.


Cela suppose que je ne l' utilise qu'enx tant que booléen, ce qui signifie que le débordement ne peut pas se produire tant que je ne l'ai pas fait ++assez souvent pour provoquer un débordement par lui-même. Même avec char comme type utilisé et CHAR_BITSquelque chose de bas comme 5, c'est 32 fois avant que cela ne fonctionne plus (c'est encore un argument suffisant pour que ce soit une mauvaise pratique, je ne défends pas la pratique, j'explique simplement pourquoi cela fonctionne) pour un 32 bits, intnous devrions bien sûr utiliser ++2 ^ 32 fois avant que ce soit un problème. Avec --si elle ne permettra d' falsesi j'ai commencé avec une valeur de 1 pour true, ou commencé avec 0 et utilisé ++exactement une fois avant.

Ceci est différent si nous commençons avec une valeur qui est juste quelques-uns en dessous de 0. En effet, dans un tel cas, nous pourrions vouloir ++aboutir à la falsevaleur éventuellement comme dans:

int x = -5;
while(++x)
  doSomething(x);

Cependant, cet exemple traite xcomme intpartout sauf le conditionnel, il est donc équivalent à:

int x = -5;
while(++x != 0)
  doSomething(x);

Ce qui est différent de n'utiliser xque comme booléen.

Jon Hanna
la source
1
Je vous remercie. C'est génial de savoir que je peux toujours donner des réponses aux gens comme ça, compte tenu du temps écoulé depuis que j'ai écrit une ligne de C ++ :)
Jon Hanna
8
Mais si x était égal à -1 (TRUE sur certaines plates-formes comme VB), ++ x serait FALSE.
James Curran
4
@James, en C et C ++, ce serait le cas auquel je pensais quand j'ai dit ("sauf débordement"). En fait, dans VB, tout non-zéro a une valeur de vérité TRUE (comme en C), mais ils ont -1 au lieu de 1 comme résultat d'opérations booléennes vraies car alors NOT (TRUE) est FALSE, NOT (FALSE) est TRUE, x OU TRUE est TRUE, x OR FALSE est x, x AND FALSE est FALSE et x AND TRUE est x, etc. en utilisant les mêmes opérateurs pour les opérations booléennes et bit par bit (puisque VB suppose un complément à deux donc -1 est tous les 1 bits). Cependant, cela peut provoquer d'étranges bogues dans VB si le codeur n'attrape pas que 2 (vrai) ET 4 (vrai) donne 0 (faux).
Jon Hanna
2
@JonHanna: ANSI C89 était le premier standard C. Le comité ANSI C a inventé l'en- <limits.h>tête et la CHAR_BITmacro. Avant cela, je suppose qu'il aurait pu théoriquement y avoir des implémentations où charest plus étroit que 8 bits, mais pour autant que je sache, il n'y en avait pas. En particulier, K & R1 (publié en 1978) répertorie 4 exemples d'implémentation, qui ont tous 8 bits ou 9 bits char.
Keith Thompson
1
@JonHanna: Une implémentation C conforme doit avoir CHAR_BIT >= 8. La norme ne tient pas compte des cibles où c'est difficile. (Vous pourriez avoir une implémentation non conforme, bien sûr.)
Keith Thompson
29

ANSI ISO CEI 14882 2003 (c ++ 03):

5.2.6-2

L'opérande de postfix - est décrémenté de manière analogue à l'opérateur postfix ++, sauf que l'opérande ne doit pas être de type bool. [Remarque: pour l'incrémentation et la décrémentation du préfixe, voir 5.3.2. ]

Et sans surprise ...

5.3.2-2

L'opérande du préfixe - est modifié en soustrayant 1. L'opérande ne doit pas être de type booléen. Les exigences sur l'opérande de prefix - et les propriétés de son résultat sont par ailleurs les mêmes que celles de prefix ++. [Remarque: pour l'incrémentation et la décrémentation postfixes, voir 5.2.6. ]

De plus, les 5.6.2-1 et 5.3.2-1 mentionnent que ++ pour les booléens sera vrai et l'annexe D-1 dit que ++ sur les booléens est obsolète.

Mainframe nordique
la source
3
@BlueRaja: Voir la réponse de Jon Hanna.
Justin Ardini
9

Pour des raisons historiques, cela a été soutenu. Mais notez que ... L'utilisation d'un opérande de type bool avec l'opérateur ++ est déconseillée voir Section 5.3.2 dans la norme C ++ (n3092)

5.3.2 Incrémenter et décrémenter [expr.pre.incr]

  • L'opérande de prefix ++ est modifié en ajoutant 1, ou mis à true s'il est booléen (cette utilisation est déconseillée). L'opérande doit être une valeur l modifiable. Le type de l'opérande doit être un type arithmétique ou un pointeur vers un type d'objet complètement défini. Le résultat est l'opérande mis à jour; c'est une lvalue, et c'est un champ de bits si l'opérande est un champ de bits. Si x n'est pas de type booléen, l'expression ++ x équivaut à x + = 1 [Note: voir les discussions sur les opérateurs d'addition (5.7) et d'assignation (5.17) pour plus d'informations sur les conversions. —End note]
  • L'opérande du préfixe - est modifié en soustrayant 1. L'opérande ne doit pas être de type booléen. Les exigences sur l'opérande de prefix - et les propriétés de son résultat sont par ailleurs les mêmes que celles de prefix ++.
Abhay
la source
3
  • Avec les anciens standards (C ++ 98) ce n'est pas une erreur.
  • Avec les nouvelles normes, l'incrémentation d'un booléen est obsolète. (C ++ 11)
  • Vous pouvez utiliser l'incrémentation sur un booléen jusqu'à C ++ 17.
mustafagonul
la source