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> boolvom 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 boolanderen als einen zu implementieren int). Wenn Sie Glück haben, kann dies auch zu einer strengeren Typprüfung beim Kompilieren führen.
intfü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 ints 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 fullanstelle 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 !notfulles 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?
aund bvon Null hochzuzählen a > 0 == b > 0. Wenn Sie darauf bestehen, die Wahrhaftigkeit beliebiger Werte ungleich Null auszunutzen, erhalten Sie !!varden booleschen Wert 0/1, der äquivalent ist var, sodass Sie schreiben können !!a == !!b, obwohl einige Leser dies verwirrend finden.
!a == !bist auch ausreichend, um die Gleichheit zu testen, Nicht-Nullen werden Null und Nullen werden Eins.
!!aals "nicht-boolesches a in seinen äquivalenten Wahrheitswert konvertieren" lesen, während ich !aals "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 trueund 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 myfalseWert 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, falseund boolsind 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 -Wallgibt keine Warnungen, also vertraue ich gcc; Wenn dies auch für funktioniert, c89sollte es auch funktionieren c99.
!kann nur Werte zurückgeben 0und 1weist daher true = !falseimmer 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, falseund bool. Oder ist es nicht, und die Verwendung _Bool, 1und 0stattdessen.
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 boolsich 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, bwürde eingestellt werden , um false iff a Null war, und truesonst. C11 6.3.1.2p1
- Wenn ein Skalarwert in konvertiert wird,
_Boolist 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 typedefan Ort und Stelle, das doublewäre einen gezwungen werden int- wenn der Wert des Doppels ist nicht in dem Bereich für intdas Verhalten ist nicht definiert .
Gleiches gilt natürlich auch, wenn trueund falsein 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:
intund Werte 0und 1 wie sie sind ; und führen Sie sorgfältig Domain-Konvertierungen von anderen Werten zu diesen mit doppelter Negation durch!!BOOL, TRUEund FALSE!intoder unsigned inteine 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 = 1nach dem C-Standard und !a = 0für jeden Wert ungleich Null von a. Das Problem ist, dass jede Nicht-Null als wahr angesehen wird. Also , wenn aund bbeide „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.
boolein Makro sein, das erweitert wird _Bool. Der Unterschied ist wichtig, weil Sie #undefein Makro können (und das ist zumindest als Übergangsmaßnahme zulässig), aber Sie können kein untypedeftypedef. 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:
_Booloder bool? Beide sind in Ordnung, sehen aber boolbesser aus als das Schlüsselwort _Bool.boolund _Boolsind: falseoder true. Zuweisen 0oder 1anstelle von falseoder trueist gültig, aber es ist schwieriger, den Logikfluss zu lesen und zu verstehen.Einige Infos aus dem Standard:
_Boolist NICHT unsigned int, ist aber Teil der Gruppe vorzeichenloser Ganzzahltypen . Es ist groß genug, um die Werte 0oder zu halten 1.bool trueund falsedas ist sicher keine gute Idee. Diese Fähigkeit gilt als veraltet und wird in Zukunft entfernt._Booloder bool, wenn der Skalarwert gleich ist 0oder mit diesem verglichen 0wird, ist 0, andernfalls lautet das Ergebnis 1: _Bool x = 9; 9wird konvertiert, 1wenn es zugewiesen wird x._Boolist 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 charmit 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 _BoolTyp verwenden. Es #includesind keine s erforderlich. Sie müssen es jedoch wie eine Ganzzahl behandeln, wo 1ist trueund 0ist false.
Sie können dann TRUEund 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, trueund falsewie der Standard es wünscht.
Sie können die #defineDirektive 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
argund 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 arg23 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.