bool operator ++ und -

104

Heute bin ich beim Schreiben von Visual C ++ - Code auf etwas gestoßen, das mich überrascht hat. Es scheint, dass C ++ ++ (Inkrement) für Bool unterstützt, aber nicht - (Dekrement). Ist dies nur eine zufällige Entscheidung, oder gibt es einen Grund dafür?

Dies kompiliert:

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

Das tut nicht:

static HMODULE hMod = NULL;
static bool once = true;
if (once--)
    hMod = LoadLibrary("xxx");
Suma
quelle
2
hm, das gleiche gilt für xcode und gcc compiler
Vladimir
Ja, ++onceund once++arbeite mit gcc, aber nicht mit den Dekrementen.
Justin Ardini
Vielleicht "Geschichte" anstelle von "Operator-Schlüsselwort" neu markieren, also wird dies mit all den anderen lustigen Erklärungen gruppiert, warum verschiedene verrückte Dinge vernünftig sind, wenn man die Geschichte betrachtet? :)
Jon Hanna
Beachten Sie, dass ab C ++ 17 der Vorinkrementierungsoperator für boolveraltet ist .
Google
Dies kann durch std::exchange(once,false)(Hinweis: nicht atomar) ersetzt werden, wenn Sie etwas nicht veraltetes möchten.
Golvok

Antworten:

90

Es stammt aus der Geschichte der Verwendung von Ganzzahlwerten als Boolesche Werte.

Wenn dies ein xist int, aber ich es als Booleschen if(x)...Wert gemäß gemäß Inkrementierung verwende, bedeutet dies, dass unabhängig von seinem Wahrheitswert vor der Operation ein Wahrheitswert von truedanach vorliegt (außer bei Überlauf).

Es ist jedoch unmöglich, das Ergebnis des --gegebenen Wissens nur über den Wahrheitswert von vorherzusagen x, da dies zu false(wenn der Integralwert 1 ist) oder true(wenn der Integralwert etwas anderes ist - insbesondere zu 0 [ false] und 2 oder mehr [ true]).

Also als Short-Hand ++gearbeitet und --nicht.

++ ist auf Bools aus Kompatibilitätsgründen zulässig, seine Verwendung ist jedoch im Standard veraltet.


Dies setzt voraus , dass ich nur verwenden xals boolean, dass Überlauf bedeutet , kann nicht passieren , bis ich getan habe ++oft genug , um einen Überlauf zu verursachen , auf seine eigene ist. Selbst mit char als verwendetem Typ und CHAR_BITSetwas Niedrigem wie 5 ist das 32 Mal, bevor dies nicht mehr funktioniert (das ist immer noch ein Argument genug, um eine schlechte Praxis zu sein, ich verteidige die Praxis nicht, sondern erkläre nur, warum sie funktioniert). Für ein 32-Bit intmüssten wir natürlich ++2 ^ 32 mal verwenden, bevor dies ein Problem ist. Mit --obwohl wird es nur ergeben, falsewenn ich mit einem Wert von 1 für trueoder mit 0 angefangen und ++genau einmal zuvor verwendet habe.

Dies ist anders, wenn wir mit einem Wert beginnen, der nur wenige unter 0 liegt. In einem solchen Fall möchten wir möglicherweise ++den falseWert schließlich wie folgt erhalten :

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

Doch dieses Beispiel behandelt xals intüberall mit Ausnahme der Bedingung, so ist es gleichbedeutend mit:

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

Was sich von der Verwendung nur xals Boolescher Wert unterscheidet.

Jon Hanna
quelle
1
Danke dir. Schön zu wissen, dass ich immer noch Antworten geben kann, wenn man bedenkt, wie lange es her ist, seit ich tatsächlich eine Zeile C ++ geschrieben habe :)
Jon Hanna
8
Aber wenn x -1 wäre (TRUE auf einigen Plattformen wie VB), wäre ++ x FALSE.
James Curran
4
@ James, in C und C ++ wäre das der Fall, an den ich gedacht habe, als ich sagte ("Überlauf ausschließen"). Tatsächlich hat in VB jede Nicht-Null den Wahrheitswert TRUE (wie in C), aber sie haben -1 anstelle von 1 als Ergebnis echter boolescher Operationen, da dann NOT (TRUE) FALSE ist, NOT (FALSE) TRUE, x OR TRUE ist TRUE, x OR FALSE ist x, x AND FALSE ist FALSE und x AND TRUE ist x usw. unter Verwendung der gleichen Operatoren für boolesche und bitweise Operationen (da VB ein Zweierkomplement annimmt, ist -1 alle 1 Bits). Dies kann jedoch einige seltsame Fehler in VB verursachen, wenn der Codierer nicht erkennt, dass 2 (wahr) UND 4 (wahr) 0 (falsch) ergeben.
Jon Hanna
2
@ JonHanna: ANSI C89 war der erste C-Standard. Das ANSI C-Komitee hat den <limits.h>Header und das CHAR_BITMakro erfunden . Zuvor hätte es theoretisch Implementierungen geben können, die charschmaler als 8 Bit sind, aber meines Wissens gab es keine. Insbesondere listet K & R1 (veröffentlicht 1978) 4 Beispielimplementierungen auf, die alle 8-Bit oder 9-Bit haben char.
Keith Thompson
1
@ JonHanna: Eine konforme C-Implementierung muss haben CHAR_BIT >= 8. Der Standard berücksichtigt keine Ziele, bei denen dies schwierig ist. (Sie könnten natürlich eine nicht konforme Implementierung haben.)
Keith Thompson
29

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

5.2.6-2

Der Operand von postfix - wird analog zum postfix ++ - Operator dekrementiert, außer dass der Operand nicht vom Typ bool sein darf. [Hinweis: Informationen zum Inkrementieren und Dekrementieren von Präfixen finden Sie unter 5.3.2. ]]

Und nicht überraschend ...

5.3.2-2

Der Operand des Präfixes - wird durch Subtrahieren von 1 geändert. Der Operand darf nicht vom Typ bool sein. Die Anforderungen an den Operanden des Präfixes - und die Eigenschaften seines Ergebnisses sind ansonsten dieselben wie die des Präfix ++. [Hinweis: Informationen zum Inkrementieren und Dekrementieren von Postfixes finden Sie unter 5.2.6. ]]

Auch in 5.6.2-1 und 5.3.2-1 wird erwähnt, dass ++ für Bools wahr sein soll, und Anhang D-1 besagt, dass ++ für Bools veraltet ist.

Nordischer Mainframe
quelle
3
@ BlueRaja: Siehe Jon Hannas Antwort.
Justin Ardini
9

Aus historischen Gründen wurde dies unterstützt. Beachten Sie jedoch Folgendes: Die Verwendung eines Operanden vom Typ bool mit dem Operator ++ ist veraltet, siehe Abschnitt 5.3.2 im C ++ - Standard (n3092).

5.3.2 Inkrementieren und Dekrementieren [expr.pre.incr]

  • Der Operand von Präfix ++ wird durch Hinzufügen von 1 geändert oder auf true gesetzt, wenn es sich um Bool handelt (diese Verwendung ist veraltet). Der Operand muss ein veränderbarer Wert sein. Der Typ des Operanden muss ein arithmetischer Typ oder ein Zeiger auf einen vollständig definierten Objekttyp sein. Das Ergebnis ist der aktualisierte Operand. Es ist ein l-Wert und ein Bitfeld, wenn der Operand ein Bitfeld ist. Wenn x nicht vom Typ bool ist, entspricht der Ausdruck ++ x x + = 1 [Hinweis: Informationen zu Konvertierungen finden Sie in den Erläuterungen zu Additions- (5.7) und Zuweisungsoperatoren (5.17). - Endnote]
  • Der Operand des Präfixes - wird durch Subtrahieren von 1 geändert. Der Operand darf nicht vom Typ bool sein. Die Anforderungen an den Operanden des Präfixes - und die Eigenschaften seines Ergebnisses sind ansonsten dieselben wie die des Präfix ++.
Abhay
quelle
3
  • Mit den alten Standards (C ++ 98) ist es kein Fehler.
  • Mit dem Inkrementieren der neuen Standards wird ein Boolescher Wert veraltet. (C ++ 11)
  • Sie können die Inkrementierung für einen Booleschen Wert bis C ++ 17 verwenden.
mustafagonul
quelle