operatore bool ++ e -


104

Oggi mentre scrivevo del codice Visual C ++ mi sono imbattuto in qualcosa che mi ha sorpreso. Sembra che C ++ supporti ++ (incremento) per bool, ma non - (decremento). È solo una decisione casuale o c'è qualche motivo dietro questo?

Questo compila:

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

Questo non:

static HMODULE hMod = NULL;
static bool once = true;
if (once--)
    hMod = LoadLibrary("xxx");

2
hm, lo stesso per xcode e il compilatore gcc
Vladimir

Sì, ++oncee once++lavora con gcc, ma non con i decrementi.
Justin Ardini

Forse rimodellare "storia" invece di "parola chiave operatore", quindi questo è raggruppato con tutte le altre spiegazioni divertenti sul perché varie cose folli sono ragionevoli se si considera la storia? :)
Jon Hanna

Nota a partire da C ++ 17 l'operatore di pre-incremento per boolè deprecato, souce .
cogle

questo può essere sostituito con std::exchange(once,false)(nota: non atomico), se vuoi qualcosa di non deprecato.
golvok

Risposte:


90

Proviene dalla storia dell'utilizzo di valori interi come valori booleani.

Se xè un int, ma lo sto usando come booleano, if(x)...quindi l'incremento significherà che qualunque sia il suo valore di verità prima dell'operazione, avrà un valore di verità truedopo di esso (salvo overflow).

Tuttavia, è impossibile prevedere il risultato di una --data conoscenza solo del valore di verità di x, poiché potrebbe risultare in false(se il valore integrale è 1) o true(se il valore integrale è qualcos'altro - in particolare questo include 0 [ false] e 2 o più [ true]).

Quindi come una mano corta ha ++funzionato, e --non l'ha fatto.

++ è consentito su bool per compatibilità con questo, ma il suo uso è deprecato nello standard.


Ciò presuppone che io usi solox come booleano, il che significa che l'overflow non può verificarsi fino a quando non l'ho fatto ++abbastanza spesso da causare un overflow da solo. Anche con char come tipo usato e CHAR_BITSqualcosa di basso come 5, è 32 volte prima che questo non funzioni più (è ancora un argomento sufficiente perché è una cattiva pratica, non sto difendendo la pratica, spiegando solo perché funziona) per un 32 bit intdovremmo ovviamente usare ++2 ^ 32 volte prima che questo sia un problema. Con --sebbene risulterà solo falsese ho iniziato con un valore di 1 per true, o se ho iniziato con 0 e usato ++esattamente una volta prima.

Questo è diverso se iniziamo con un valore che è solo alcuni sotto lo 0. In effetti, in tal caso potremmo voler ++restituire il falsevalore alla fine come in:

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

Tuttavia, questo esempio tratta xcome un intovunque tranne il condizionale, quindi è equivalente a:

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

Che è diverso dall'uso solo xcome booleano.


1
Grazie. Bello sapere che posso ancora dare risposte a persone come questo, dato quanto tempo è passato da quando ho effettivamente scritto una riga di C ++ :)
Jon Hanna

8
Ma se x fosse -1 (TRUE in alcune piattaforme come VB), ++ x sarebbe FALSE.
James Curran

4
@ James, in C e C ++ sarebbe il caso a cui stavo pensando quando ho detto ("salvo overflow"). In realtà in VB qualsiasi diverso da zero ha valore di verità TRUE (come in C), ma hanno -1 invece di 1 come risultato di vere operazioni booleane poiché quindi NOT (TRUE) è FALSE, NOT (FALSE) è TRUE, x OR TRUE è TRUE, x OR FALSE è x, x AND FALSE è FALSE e x AND TRUE è x, ecc. Utilizzando gli stessi operatori per operazioni booleane e bit per bit (poiché VB presuppone il complemento a due, quindi -1 è tutto 1 bit). Tuttavia, questo può causare alcuni strani bug in VB se il programmatore non rileva che 2 (vero) E 4 (vero) restituisce 0 (falso).
Jon Hanna

2
@ JonHanna: ANSI C89 è stato il primo standard C. Il comitato ANSI C ha inventato l' <limits.h>intestazione e la CHAR_BITmacro. Prima di ciò, suppongo che teoricamente avrebbero potuto esserci implementazioni in cui charè più stretto di 8 bit, ma per quanto ne so non ce n'erano. In particolare, K & R1 (pubblicato nel 1978) elenca 4 implementazioni di esempio, tutte a 8 bit o 9 bit char.
Keith Thompson

1
@ JonHanna: deve avere un'implementazione C conforme CHAR_BIT >= 8. Lo standard non tiene conto degli obiettivi in ​​cui è difficile. (Potresti avere un'implementazione non conforme, ovviamente.)
Keith Thompson,

29

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

5.2.6-2

L'operando di postfix - è decrementato in modo analogo all'operatore postfix ++, tranne per il fatto che l'operando non deve essere di tipo bool. [Nota: per l'incremento e il decremento del prefisso, vedere 5.3.2. ]

E non sorprende ...

5.3.2-2

L'operando di prefix - viene modificato sottraendo 1. L'operando non deve essere di tipo bool. I requisiti dell'operando di prefix - e le proprietà del suo risultato sono per il resto gli stessi di prefix ++. [Nota: per l'incremento e il decremento del suffisso, vedere 5.2.6. ]

Anche 5.6.2-1 e 5.3.2-1 menzionano che ++ per bools deve essere vero e l'Allegato D-1 dice che ++ su bools è deprecato.


3
@BlueRaja: vedi la risposta di Jon Hanna.
Justin Ardini

9

Per motivi storici questo è stato supportato. Si noti che ... L'uso di un operando di tipo bool con l'operatore ++ è deprecato, vedere la Sezione 5.3.2 nello standard C ++ (n3092)

5.3.2 Incremento e decremento [expr.pre.incr]

  • L'operando del prefisso ++ viene modificato aggiungendo 1 o impostato su true se è bool (questo uso è deprecato). L'operando deve essere un valore modificabile. Il tipo dell'operando deve essere un tipo aritmetico o un puntatore a un tipo di oggetto completamente definito. Il risultato è l'operando aggiornato; è un lvalue, ed è un campo di bit se l'operando è un campo di bit. Se x non è di tipo bool, l'espressione ++ x è equivalente a x + = 1 [Nota: vedere le discussioni sull'addizione (5.7) e sugli operatori di assegnazione (5.17) per informazioni sulle conversioni. —End nota]
  • L'operando di prefix - viene modificato sottraendo 1. L'operando non deve essere di tipo bool. I requisiti dell'operando di prefix - e le proprietà del suo risultato sono per il resto gli stessi di prefix ++.

3
  • Con i vecchi standard (C ++ 98) non è un errore.
  • Con i nuovi standard l'incremento di un valore booleano è deprecato. (C ++ 11)
  • È possibile utilizzare l'incremento su un valore booleano fino a C ++ 17.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.