C hat keine eingebauten booleschen Typen. Was ist der beste Weg, um sie in C zu verwenden?
C hat keine eingebauten booleschen Typen. Was ist der beste Weg, um sie in C zu verwenden?
Antworten:
Vom Besten zum Schlechten:
Option 1 (C99)
#include <stdbool.h>
Option 2
typedef enum { false, true } bool;
Option 3
typedef int bool;
enum { false, true };
Option 4
typedef int bool;
#define true 1
#define false 0
Wenn Sie unentschlossen sind, gehen Sie mit # 1!
<stdbool.h>
bool
vom Compiler ausgewählten Werts ist möglicherweise für den beabsichtigten Zweck eines booleschen Werts besser geeignet als die Verwendung eines int
(dh der Compiler kann sich dafür entscheiden, einen bool
anderen als einen zu implementieren int
). Wenn Sie Glück haben, kann dies auch zu einer strengeren Typprüfung beim Kompilieren führen.
int
für verwenden bool
? Das ist verschwenderisch. Verwenden Sie unsigned char
. Oder C des builtin verwenden _Bool
.
Ein paar Gedanken zu Booleschen Werten in C:
Ich bin alt genug, dass ich nur einfaches int
s als meinen booleschen Typ verwende, ohne typedefs oder spezielle Definitionen oder Aufzählungen für wahre / falsche Werte. Wenn Sie meinem Vorschlag unten folgen, niemals mit booleschen Konstanten zu vergleichen, müssen Sie ohnehin nur 0/1 verwenden, um die Flags zu initialisieren. Ein solcher Ansatz kann jedoch in diesen modernen Zeiten als zu reaktionär angesehen werden. In diesem Fall sollte man auf jeden Fall verwenden, <stdbool.h>
da es zumindest den Vorteil hat, standardisiert zu werden.
Unabhängig davon, wie die booleschen Konstanten heißen, verwenden Sie sie nur zur Initialisierung. Schreibe niemals so etwas
if (ready == TRUE) ...
while (empty == FALSE) ...
Diese können immer durch den Reiniger ersetzt werden
if (ready) ...
while (!empty) ...
Beachten Sie, dass diese tatsächlich vernünftigerweise und verständlich laut vorgelesen werden können.
Geben Sie Ihren booleschen Variablen positive Namen, dh full
anstelle von notfull
. Letzteres führt zu schwer lesbarem Code. Vergleichen Sie
if (full) ...
if (!full) ...
mit
if (!notfull) ...
if (notfull) ...
Beide der ersteren Paare lesen natürlich, während !notfull
es schwierig ist, es zu lesen, und es wird in komplexeren booleschen Ausdrücken viel schlimmer.
Boolesche Argumente sollten generell vermieden werden. Stellen Sie sich eine so definierte Funktion vor
void foo(bool option) { ... }
Innerhalb des Hauptteils der Funktion ist sehr klar, was das Argument bedeutet, da es einen bequemen und hoffentlich bedeutungsvollen Namen hat. Die Anrufseiten sehen jedoch so aus
foo(TRUE);
foo(FALSE):
Hier ist es im Wesentlichen unmöglich zu sagen, was der Parameter bedeutet, ohne immer die Funktionsdefinition oder Deklaration zu betrachten, und es wird viel schlimmer, sobald Sie noch mehr boolesche Parameter hinzufügen. Ich schlage auch vor
typedef enum { OPT_ON, OPT_OFF } foo_option;
void foo(foo_option option);
oder
#define OPT_ON true
#define OPT_OFF false
void foo(bool option) { ... }
In beiden Fällen sieht die Anrufseite jetzt so aus
foo(OPT_ON);
foo(OPT_OFF);
was der Leser zumindest eine Chance hat zu verstehen, ohne die Definition von auszubaggern foo
.
a == b
?
a
und b
von Null hochzuzählen a > 0 == b > 0
. Wenn Sie darauf bestehen, die Wahrhaftigkeit beliebiger Werte ungleich Null auszunutzen, erhalten Sie !!var
den booleschen Wert 0/1, der äquivalent ist var
, sodass Sie schreiben können !!a == !!b
, obwohl einige Leser dies verwirrend finden.
!a == !b
ist auch ausreichend, um die Gleichheit zu testen, Nicht-Nullen werden Null und Nullen werden Eins.
!!a
als "nicht-boolesches a in seinen äquivalenten Wahrheitswert konvertieren" lesen, während ich !a
als "logisch invertieren der booleschen Variablen a" lesen würde . Insbesondere würde ich nach einem bestimmten Grund suchen, aus dem die logische Umkehrung gewünscht wurde.
Ein Boolescher Wert in C ist eine Ganzzahl: Null für falsch und Nicht-Null für wahr.
Siehe auch Boolescher Datentyp , Abschnitt C, C ++, Objective-C, AWK .
Hier ist die Version, die ich verwendet habe:
typedef enum { false = 0, true = !false } bool;
Da false nur einen Wert hat, ein logisches true jedoch viele Werte haben kann, setzt die Technik true so, wie es der Compiler für das Gegenteil von false verwendet.
Dies behebt das Problem, dass jemand etwas codiert, das darauf zurückzuführen wäre:
if (true == !false)
Ich denke, wir sind uns alle einig, dass dies keine gute Praxis ist, aber für die einmaligen Kosten für "true =! False" beseitigen wir dieses Problem.
[EDIT] Am Ende habe ich verwendet:
typedef enum { myfalse = 0, mytrue = !myfalse } mybool;
um eine Namenskollision mit anderen Schemata zu vermeiden, die true
und definiert wurden false
. Das Konzept bleibt jedoch dasselbe.
[EDIT] So zeigen Sie die Konvertierung einer Ganzzahl in einen Booleschen Wert an:
mybool somebool;
int someint = 5;
somebool = !!someint;
Der erste (ganz rechts)! wandelt die Ganzzahl ungleich Null in eine 0 um, dann die zweite (ganz links)! wandelt die 0 in einen myfalse
Wert um. Ich werde es dem Leser als Übung überlassen, eine Null-Ganzzahl umzuwandeln.
[BEARBEITEN] Es ist mein Stil, die explizite Einstellung eines Werts in einer Aufzählung zu verwenden, wenn der spezifische Wert erforderlich ist, selbst wenn der Standardwert der gleiche wäre. Beispiel: Da false Null sein muss, verwende ich false = 0,
eher alsfalse,
true
, false
und bool
sind die in den meisten IDE hervorgehoben , weil sie ENUM - Werte und ein typedef sind, im Gegensatz zu #defines
, die sind selten jemals Syntax - Hervorhebungen.
gcc -ansi -pedantic -Wall
gibt keine Warnungen, also vertraue ich gcc
; Wenn dies auch für funktioniert, c89
sollte es auch funktionieren c99
.
!
kann nur Werte zurückgeben 0
und 1
weist daher true = !false
immer den Wert 1 zu. Diese Methode bietet keine zusätzliche Sicherheit typedef enum { false, true } bool;
.
if(!value)
) nicht von Bedeutung ist, aber diese Ausnahme gilt in diesem speziellen Fall nicht.
Wenn Sie einen C99-Compiler verwenden, bietet dieser eine integrierte Unterstützung für Bool-Typen:
#include <stdbool.h>
int main()
{
bool b = false;
b = true;
}
Das wichtigste zuerst. C, dh ISO / IEC 9899 hat seit 19 Jahren einen booleschen Typ . Das ist viel länger als die erwartete Länge der C-Programmierkarriere mit Amateur- / akademischen / professionellen Teilen, die beim Besuch dieser Frage kombiniert werden . Meins übertrifft das nur um 1-2 Jahre. Dies bedeutet, dass während der Zeit , in der ein durchschnittlicher Leser überhaupt etwas über C gelernt hat, C tatsächlich den booleschen Datentyp hatte .
Für den Datentyp #include <stdbool.h>
und Verwendung true
, false
und bool
. Oder ist es nicht, und die Verwendung _Bool
, 1
und 0
stattdessen.
In den anderen Antworten auf diesen Thread werden verschiedene gefährliche Praktiken beschrieben. Ich werde sie ansprechen:
typedef int bool;
#define true 1
#define false 0
Dies ist ein Nein-Nein, da ein Gelegenheitsleser - der in diesen 19 Jahren C gelernt hat - erwarten würde, dass bool
sich dies auf den tatsächlichen bool
Datentyp bezieht und sich ähnlich verhält, dies jedoch nicht! Zum Beispiel
double a = ...;
bool b = a;
Mit C99 bool
/ _Bool
, b
würde eingestellt werden , um false
iff a
Null war, und true
sonst. C11 6.3.1.2p1
- Wenn ein Skalarwert in konvertiert wird,
_Bool
ist das Ergebnis 0, wenn der Wert gleich 0 ist. Andernfalls ist das Ergebnis 1. 59)Fußnoten
59) NaNs sind nicht gleich 0 und wandeln sich daher in 1 um.
Mit dem typedef
an Ort und Stelle, das double
wäre einen gezwungen werden int
- wenn der Wert des Doppels ist nicht in dem Bereich für int
das Verhalten ist nicht definiert .
Gleiches gilt natürlich auch, wenn true
und false
in einem deklariert wurden enum
.
Was noch gefährlicher ist, ist zu erklären
typedef enum bool {
false, true
} bool;
Da jetzt alle Werte außer 1 und 0 ungültig sind und ein solcher Wert einer Variablen dieses Typs zugewiesen werden sollte, wäre das Verhalten völlig undefiniert .
Daher iff Sie nicht C99 aus unerklärlichen Gründen, für boolean Variablen verwenden können , sollten Sie verwenden:
int
und Werte 0
und 1
wie sie sind ; und führen Sie sorgfältig Domain-Konvertierungen von anderen Werten zu diesen mit doppelter Negation durch!!
BOOL
, TRUE
und FALSE
!int
oder unsigned int
eine Aufzählung zu halten, aber ich weiß von nichts in der Norm , die eine Aufzählung verursachen würde als etwas anderes als eine ganze Zahl verhalten Art.
typedef enum {
false = 0,
true
} t_bool;
!0 = 1
nach dem C-Standard und !a = 0
für jeden Wert ungleich Null von a
. Das Problem ist, dass jede Nicht-Null als wahr angesehen wird. Also , wenn a
und b
beide „wahr“ ist , ist es nicht unbedingt der Fall , dass `a == b '.
C hat einen booleschen Typ: bool (zumindest für die letzten 10 (!) Jahre)
Fügen Sie stdbool.h hinzu und true / false funktioniert wie erwartet.
bool
ein Makro sein, das erweitert wird _Bool
. Der Unterschied ist wichtig, weil Sie #undef
ein Makro können (und das ist zumindest als Übergangsmaßnahme zulässig), aber Sie können kein untypedef
typedef. Es ändert jedoch nichts an der Hauptausrichtung Ihres ersten Kommentars.
Alles, was ungleich Null ist, wird in booleschen Operationen als wahr ausgewertet
#define TRUE 1
#define FALSE 0
und benutze die Konstanten.
Nur eine Ergänzung zu anderen Antworten und einige Erläuterungen, wenn Sie C99 verwenden dürfen.
+-------+----------------+-------------------------+--------------------+
| Name | Characteristic | Dependence in stdbool.h | Value |
+-------+----------------+-------------------------+--------------------+
| _Bool | Native type | Don't need header | |
+-------+----------------+-------------------------+--------------------+
| bool | Macro | Yes | Translate to _Bool |
+-------+----------------+-------------------------+--------------------+
| true | Macro | Yes | Translate to 1 |
+-------+----------------+-------------------------+--------------------+
| false | Macro | Yes | Translate to 0 |
+-------+----------------+-------------------------+--------------------+
Einige meiner Vorlieben:
_Bool
oder bool
? Beide sind in Ordnung, sehen aber bool
besser aus als das Schlüsselwort _Bool
.bool
und _Bool
sind: false
oder true
. Zuweisen 0
oder 1
anstelle von false
oder true
ist gültig, aber es ist schwieriger, den Logikfluss zu lesen und zu verstehen.Einige Infos aus dem Standard:
_Bool
ist NICHT unsigned int
, ist aber Teil der Gruppe vorzeichenloser Ganzzahltypen . Es ist groß genug, um die Werte 0
oder zu halten 1
.bool
true
und false
das ist sicher keine gute Idee. Diese Fähigkeit gilt als veraltet und wird in Zukunft entfernt._Bool
oder bool
, wenn der Skalarwert gleich ist 0
oder mit diesem verglichen 0
wird, ist 0
, andernfalls lautet das Ergebnis 1
: _Bool x = 9;
9
wird konvertiert, 1
wenn es zugewiesen wird x
._Bool
ist 1 Byte (8 Bit), normalerweise ist der Programmierer versucht, die anderen Bits zu verwenden, wird jedoch nicht empfohlen, da nur garantiert wird, dass nur ein Bit zum Speichern von Daten verwendet wird, nicht wie bei einem Typ char
mit 8 Bits verfügbar.Sie können ein Zeichen oder einen anderen Container mit kleiner Nummer dafür verwenden.
Pseudocode
#define TRUE 1
#define FALSE 0
char bValue = TRUE;
int
), da Sie bei einigen Architekturen einen erheblichen Leistungseinbruch erzielen, wenn Sie diese Variablen entpacken / maskieren müssen.
Sie könnten _Bool verwenden, aber der Rückgabewert muss eine Ganzzahl sein (1 für wahr, 0 für falsch). Es wird jedoch empfohlen, bool wie in C ++ einzuschließen und zu verwenden, wie in dieser Antwort aus dem daniweb-Forum sowie in dieser Antwort aus dieser anderen Stackoverflow-Frage angegeben:
_Bool: Der boolesche Typ von C99. Die direkte Verwendung von _Bool wird nur empfohlen, wenn Sie Legacy-Code verwalten, der bereits Makros für bool, true oder false definiert. Andernfalls werden diese Makros im Header standardisiert. Wenn Sie diesen Header einschließen, können Sie bool wie in C ++ verwenden.
Bedingte Ausdrücke gelten als wahr, wenn sie nicht Null sind. Der C-Standard verlangt jedoch, dass logische Operatoren selbst entweder 0 oder 1 zurückgeben.
@ Tom: #define TRUE! FALSE ist schlecht und völlig sinnlos. Wenn die Header-Datei in kompilierten C ++ - Code gelangt, kann dies zu Problemen führen:
void foo(bool flag);
...
int flag = TRUE;
foo(flag);
Einige Compiler generieren eine Warnung über die Konvertierung von int => bool. Manchmal vermeiden die Leute dies, indem sie Folgendes tun:
foo(flag == TRUE);
um den Ausdruck als C ++ - Bool zu erzwingen. Aber wenn Sie TRUE! FALSE definieren, erhalten Sie:
foo(flag == !0);
Dies führt zu einem Int-to-Bool-Vergleich, der die Warnung trotzdem auslösen kann.
Wenn Sie C99 verwenden, können Sie den _Bool
Typ verwenden. Es #include
sind keine s erforderlich. Sie müssen es jedoch wie eine Ganzzahl behandeln, wo 1
ist true
und 0
ist false
.
Sie können dann TRUE
und definieren FALSE
.
_Bool this_is_a_Boolean_var = 1;
//or using it with true and false
#define TRUE 1
#define FALSE 0
_Bool var = TRUE;
#include <stdbool.h>
und verwenden bool
, true
und false
wie der Standard es wünscht.
Sie können die #define
Direktive einfach wie folgt verwenden:
#define TRUE 1
#define FALSE 0
#define NOT(arg) (arg == TRUE)? FALSE : TRUE
typedef int bool;
Und verwenden Sie wie folgt:
bool isVisible = FALSE;
bool isWorking = TRUE;
isVisible = NOT(isVisible);
und so weiter
arg
und den Ausdruck als Ganzes geschützt werden : #define NOT(arg) (((arg) == TRUE) ? FALSE : TRUE)
. Es wäre jedoch besser, auf Falschheit zu testen (es wird die richtige Antwort geben, selbst wenn arg
23 statt 0 oder 1 war : #define NOT(arg) (((arg) == FALSE) ? TRUE : FALSE)
. Aber der gesamte Ausdruck kann #define NOT(arg) (!(arg))
natürlich auf das reduziert werden , was das gleiche Ergebnis liefert.