Verwenden von wahr und falsch in C.


74

Soweit ich sehen kann, gibt es in c drei Möglichkeiten, Boolesche Werte zu verwenden

  1. mit dem Bool-Typ, von da an mit true und false
  2. Definieren mit Präprozessor #define FALSE 0 ... #define TRUE !(FALSE)
  3. Nur um Konstanten direkt zu verwenden, dh 1 und 0

Gibt es andere Methoden, die ich verpasst habe? Was sind die Vor- und Nachteile der verschiedenen Methoden?

Ich nehme an, die schnellste wäre Nummer 3, 2 ist noch leichter lesbar (obwohl die bitweise Negation den Overhead geringfügig erhöht), 1 ist am besten lesbar und nicht mit allen Compilern kompatibel.


37
Sie glauben tatsächlich, dass die Compiler bis zur Laufzeit warten werden, um eine Konstante zu negieren?
GManNickG

23
Um nachzufolgen, damit ich nicht wie ein Idiot aussehe, wird kein Compiler seine Zeit damit verschwenden. Compiler sind starke Optimierer, und wenn sie wissen, dass die Ergebnisse immer gleich sind, werden sie stattdessen dort abgelegt. Die Auswertung wird niemals bis zur Laufzeit warten int i = 12 + 3 * 4;. es wird nur sagen int i = 24;. Sorgen Sie sich nicht schlecht um solche Leistung, ein häufiges Problem. Optimierungen kommen als letztes , und wenn sie kommen, müssen Sie Ihren Code zeitlich festlegen und die Assembly-Ausgabe betrachten, nicht raten. Selbst wenn es einen Zyklus kosten würde, würde ich mich für die am besten lesbare Lösung entscheiden. Nur als es sich als a
GManNickG

11
Problem würde ich zu einer schnelleren Lösung wechseln und sie zeitlich festlegen, um sicherzustellen, dass sie tatsächlich schneller sind. Wenn Sie zwischen Lesbarkeit und Zyklus wählen können, wählen Sie Lesbarkeit. :) Es ist einfach, guten Code schnell zu machen, aber schwer, "schnellen" Code gut zu machen.
GManNickG

19
Denken Sie bei der Verwendung der Makros daran, dass dies (x == TRUE)nicht dasselbe ist wie (x). Ersteres gilt nur, wenn xder Wert von gilt TRUE. Letzteres gilt für jeden Wert ungleich Null.
Devon_C_Miller

6
Ich rate davon ab, spezielle boolesche Makros zu definieren. Dies verleitet nur unerfahrene Programmierer dazu, Dinge wie if(foo == TRUE)oder zu schreiben if(foo == FALSE), was in den meisten Sprachen eine Gräueltat ist, aber noch mehr in C, wo jeder skalare Wert != 0in booleschen Kontexten als wahr angesehen wird. aus ähnlichen, aber weniger schwerwiegenden Gründen mag ich nicht if(foo != NULL)und if(foo == NULL)für Hinweise; Da dies keine Fehler im Vergleich zu Dosen einführen TRUEkann, ist es nur eine Frage des Geschmacks, aber die Verwendung if(foo)und if(!foo)für jeden skalaren Wert entspricht imo mehr dem Look-and-Feel der C-Sprache
Christoph

Antworten:


116

Geben <stdbool.h>Sie einfach an, ob Ihr System dies bereitstellt. Dies definiert eine Anzahl von Makros, einschließlich bool, falseund true(definiert als _Bool, 0 bzw. 1). Weitere Informationen finden Sie in Abschnitt 7.16 von C99.


11
Kein "Bool" ist ein Makro. Der Typ ist "_Bool". Andernfalls würde der alte Code schrecklich kaputt gehen.
Lothar

6
Sie können _Boolohne Einbeziehung verwendenstdbool.h
Christoph

21

Verwenden Sie einfach 0 oder 1 direkt im Code.

Für C-Programmierer ist dies so intuitiv wie wahr oder falsch.


45
Für C-Programmierer gilt -1 ebenfalls, da es keine Null ist. Im Übrigen sind 42 und -234 ebenfalls wahre Werte. Ich habe -1, -2 und andere Werte als wahr angesehen. Einige Funktionen geben 0 (Null) als erfolgreich zurück. Hmmm, soviel zur Konsistenz.
Thomas Matthews

1
Normalerweise sehe ich nur 1 oder -1 als wahre Werte. -1, weil es nur Einsen in Binärform sind. Ich würde gerne wissen, wo Sie -2 gefunden haben.
Mike DeSimone

7
Ich stimme Thomas zu. Die Tatsache, dass 0 als Fehlercode für "kein Fehler" (und oft auch als intTyp) verwendet wird, macht es manchmal nicht offensichtlich, ob ein Wert in einem booleschen Kontext verwendet werden soll.
Jamesdlin

9
Stellen Sie sich eine Funktion vor, die 0 ohne Fehler zurückgibt, als Antwort auf die Frage "Hatten Sie ein Problem?" - "0 = falsch = nein". int fail = close(fd); if (!fail) { great(); } else { weep(); }
Squelart

1
@squelart: Das Problem ist, dass viele Funktionen, die boolesche Werte zurückgeben, diese Semantik nicht haben und bei Erfolg einen wahren Wert und bei einem Fehler einen falschen Wert zurückgeben. (Zum Beispiel ist ein Großteil der Win32-API auf diese Weise entworfen.)
Jamesdlin

17

Normalerweise mache ich:

typedef enum {FALSE = 0, TRUE} boolean;

5
Warum setzen Sie explizit FALSE = 0? Ist das erste Element einer Aufzählung nicht automatisch 0?
Lindelof

10
@ Lindelof Es ist nur für den Fall, dass sie FileNotFounddie Vorderseite dieser Aufzählung ergänzen . ;-)
Chris Jester-Young

1
@ Lindelof Es macht Sinn. Sicherzustellen, dass FALSE 0 ist, ist das einzig Wichtige. WAHR kann alles sein, solange es anders ist.
Klutt

5

Beim definierten Bool-Typ stdbool.h treten Probleme auf, wenn Sie Code von einem neueren Compiler, der den Bool-Typ unterstützt, in einen älteren Compiler verschieben müssen. Dies kann in einer eingebetteten Programmierumgebung passieren, wenn Sie mit einem C-Compiler, der auf einer älteren Version der Spezifikation basiert, zu einer neuen Architektur wechseln.

Zusammenfassend würde ich mich an die Makros halten, wenn Portabilität wichtig ist. Andernfalls tun Sie, was andere empfehlen, und verwenden Sie den Typ Bulit.


5

Unabhängig davon, mit welchen der drei Variablen Sie arbeiten, vergleichen Sie Ihre Variablen mit FALSE oder false.

Historisch gesehen ist es eine schlechte Idee, irgendetwas mit true (1) in c oder c ++ zu vergleichen. Nur false ist garantiert Null (0). True ist jeder andere Wert . Viele Compiler-Anbieter haben diese Definitionen irgendwo in ihren Headern.  

#define TRUE 1
#define FALSE 0

Dies hat zu viele Menschen den Gartenweg entlang geführt. Viele Bibliotheksfunktionen geben außerdem chartypeWerte ungleich Null zurück, die 1bei Erfolg nicht gleich sind . Es gibt eine Menge Legacy-Code mit demselben Verhalten.


2
Ich habe festgestellt, dass Vergleiche mit TRUE mit nicht initialisierten Variablen fehlschlagen. Es ist besser, Ihre Booleschen Werte zu initialisieren und mit FALSE zu vergleichen. Eine Aufzählung ist besser, wenn Sie wirklich drei Werte benötigen. Nein, ja, und weiß nicht. Initialisieren Sie die Aufzählung, um nicht zu wissen. Behandle die Aufzählung nicht so, als wäre sie boolesch. Ist es nicht.
Bob Wakefield

3

Sie können testen, ob bool in c99 stdbool.h mit definiert ist

#ifndef __bool_true_false_are_defined || __bool_true_false_are_defined == 0
//typedef or define here
#endif

Entschuldigung für meinen letzten Kommentar, meine PDF-Suchfunktion ist defekt. Weitere Informationen finden Sie in Abschnitt 7.16 __bool_true_false_are_defined.
Chris Jester-Young

2

Ich würde für 1 gehen. Ich habe keine Inkompatibilität damit getroffen und ist natürlicher. Aber ich denke, dass es ein Teil von C ++ ist, nicht C-Standard. Ich denke, dass mit schmutzigem Hacken mit Definitionen oder Ihrer dritten Option keine Leistung erzielt wird, sondern nur Schmerzen bei der Pflege des Codes.


5
boolist Teil von C ++, aber _Bool (mit boolals Alias) ist jetzt Teil von C (ab C99).
Jerry Coffin

Gut das zu wissen. Vielen Dank. :)
Anthares

Ich würde nicht für 1 gehen, da jeder Wert ungleich Null wahr ist. Bei vorzeichenbehafteten Mengen gilt also auch -1.
Thomas Matthews

Ich meine Option 1 ... mit Bool-Typ
Anthares

2

Ich bevorzuge (1), wenn ich eine Variable definiere, aber in Ausdrücken vergleiche ich nie mit wahr und falsch. Nimm einfach die implizite C-Definition von if (flag) oder if (! Flag) oder if (ptr). Das ist die C-Art, Dinge zu tun.


2

Jedes andere int als Null ist wahr; false ist Null. Auf diese Weise funktioniert Code wie dieser weiterhin wie erwartet:

int done = 0;   // `int` could be `bool` just as well

while (!done)
{
     // ...
     done = OS_SUCCESS_CODE == some_system_call ();
}

IMO boolist ein überbewerteter Typ, möglicherweise eine Übertragung aus anderen Sprachen. intfunktioniert gut als boolescher Typ.


1
Re "überbewertet": In C ++ boolhandelt es sich um einen separaten Typ, der an der Funktionsüberladung teilnehmen kann, aus dem gleichen Grund, warum Zeichenkonstanten charin C ++ vom Typ sind . Dies gilt natürlich nicht für C, das keine Funktionsüberladung aufweist.
Chris Jester-Young

5
Nein, C ist dadurch gebrochen, dass es nicht zwischen Booleschen und Ganzzahlen unterscheidet.
Starblue

1
C ist kaum kaputt. Eine Ganzzahl ist eine Menge von Booleschen Werten, die parallel bearbeitet werden können. Die Bewertung des Satzes als Ganzes ist ihr ODER-Wert.
Wallyk

1
@starblue: C99 hat einen dedizierten booleschen Typ eingeführt. Wenn es Sie beruhigt, können Sie so tun, als würde C Skalarwerte automatisch _Boolin boolesche Kontexte konvertieren , eine Funktion, die auch in vielen dynamischen Sprachen zu finden ist
Christoph

2
Das Schöne daran _Boolist, dass der Compiler es so speichern kann, wie es am besten funktioniert (ein Byte, ein Wort, ein bisschen, was auch immer). Vielleicht haben Sie sogar die Möglichkeit, die Größe beim Kompilieren zu bestimmen (wie bei einigen Compilern, bei denen Sie int2 oder 4 Bytes oder long4 oder 8 Bytes angeben können ). Haben Sie einen Prozessor, der auf Dinge als Wörter zugreifen möchte? Machen Sie _Booldie Wortgröße. Greift Ihr Prozessor so einfach auf Bytes zu wie auf Wörter? Machen Sie es zu einem Byte, um Platz zu sparen. Haben Sie Anweisungen für den Bitzugriff? Vielleicht, vielleicht nicht. Fortsetzung der langen Tradition von C, keine intGrößen festzunageln ...
Mike DeSimone

1

Früher habe ich #define verwendet, weil sie das Lesen von Code erleichtern und es keine Leistungseinbußen im Vergleich zur Verwendung von Zahlen (0,1) geben sollte, da der Präprozessor #define vor dem Kompilieren in Zahlen konvertiert. Sobald die Anwendung ausgeführt wird, kommt der Präprozessor nicht mehr in den Weg, da der Code bereits kompiliert ist.

Übrigens sollte es sein:

#define FALSE 0 
#define TRUE 1

und denken Sie daran, dass -1, -2, ... 2, 3 usw. alle als wahr ausgewertet werden.


TRUE ist ein schreibgeschützter Wert. Beim Lesen / Vergleichen usw. muss jeder Wert ungleich Null als wahr behandelt werden.
Jerry Coffin

2
Aus irgendeinem Grund scheint TRUE allgemein als #define TRUE! (FALSE) definiert zu sein
Tom

3
@Tom - Das liegt daran, dass !10 zurückgegeben wird, aber !0ein wahrer Wert zurückgegeben wird, der eine Vielzahl von Zahlen sein kann. #define TRUE !(FALSE)stellt sicher, dass TRUE == !0unabhängig davon, welcher genaue Wert !0zurückgegeben wird.
Chris Lutz

1

Ich kenne dich nicht spezifisch. Als ich C-Programme schrieb, haben wir immer # 2 verwendet.

#define FALSE = 0
#define TRUE = !FALSE

Dies könnte ansonsten unter fremder Plattform für DOS- oder Intel-basierte Prozessoren sein. Aber ich habe sowohl C als auch ASM zusammen verwendet, um Grafikbibliotheken und grafische IDE zu schreiben. Ich war ein echter Fan von Micheal Abrash und wollte etwas über Textur-Mapping und so lernen. Wie auch immer! Das ist hier nicht das Thema der Frage!

Dies war die am häufigsten verwendete Form zum Definieren von Booleschen Werten in C, da diese Headerdatei stdbool.h damals nicht vorhanden war.


1
Vielleicht möchten Sie dies tun #define TRUE = (! (FALSE))
ant2009

1
Was ist der Vorteil über #define TRUE = 1?
Endolith

3
Setzen Sie zuerst nicht das Gleichheitszeichen (=) in ein #define. Zweitens hat nur FALSE einen definierten Wert. Null. TRUE ist ein beliebiger anderer Wert.
Bob Wakefield

1

Es gibt keinen wirklichen Geschwindigkeitsunterschied. Für den Compiler sind sie wirklich alle gleich. Der Unterschied besteht darin, dass die Menschen versuchen, Ihren Code zu verwenden und zu lesen.

Für mich ist Bool, True und False die beste Wahl für C ++ - Code. In C-Code gibt es einige Compiler, die Bool nicht unterstützen (ich muss oft mit alten Systemen arbeiten), daher kann ich unter bestimmten Umständen mit den Definitionen arbeiten.


1

1 ist am besten lesbar und nicht mit allen Compilern kompatibel.

Kein ISO C-Compiler hat einen eingebauten Typ namens bool. ISO C99-Compiler haben einen Typ _Boolund einen Header, der typedef ist bool. Kompatibilität bedeutet also einfach, einen eigenen Header bereitzustellen, wenn der Compiler nicht C99-kompatibel ist (z. B. VC ++).

Ein einfacherer Ansatz ist natürlich, Ihren C-Code als C ++ zu kompilieren.


Ein C-Code mit ausreichender Komplexität wird nicht mit einem C ++ - Compiler kompiliert. Wenn Sie einen C ++ - Compiler verwenden möchten, codieren Sie C ++.
Klutt

@Broman Ich glaube nicht, dass Komplexität viel damit zu tun hat. eher subtile semantische Unterschiede. Die stärkere Typprüfung von C ++ führt zu einer Problemdiagnose, die bei der C-Kompilierung nicht auftritt. Zum größten Teil ist es möglich, solche Probleme zu beheben und den Code in beiden Sprachen sowohl gültig als auch semantisch identisch zu machen. In den meisten Fällen ist das Ergebnis in jedem Fall ein besserer Code. Es ist jedoch richtig, dass eine große (und nicht unbedingt komplexe ) C-Codebasis wahrscheinlich nicht modifiziert kompiliert wird.
Clifford

Es stimmt, dass es nicht ausschließlich um Komplexität geht. Was ich damit meinte war, dass die meisten nicht trivialen Programme einen Malloc-Aufruf enthalten, und dann müssen Sie Casting durchführen. Wenn Sie es mit einem C ++ - Compiler kompilieren möchten, warum nicht stattdessen einfach C ++ codieren?
Klutt

@Broman Wenn Sie es als C ++ kompilieren, ist es C ++, auch wenn es auch gültig ist C. Die Verwendung von malloc () und die Notwendigkeit des Castings sind eine Instanz, in der das Kompilieren des C-Codes C ++ zu einem geringfügig schlechteren C-Code führt.
Clifford

@Broman Außerdem ist es eine sehr alte Antwort. VC ++ bietet inzwischen eine viel umfassendere C99-Unterstützung, einschließlich stdbool.h. Abgesehen von C ++ galt dies wirklich nur, wenn Sie mit C90 feststeckten, was zunehmend unwahrscheinlich ist.
Clifford

0

Ich bevorzuge die dritte Lösung, dh die Verwendung von 1 und 0, da sie besonders nützlich ist, wenn Sie testen müssen, ob eine Bedingung wahr oder falsch ist: Sie können einfach eine Variable für das if-Argument verwenden.
Wenn Sie andere Methoden verwenden, sollte ich, um mit dem Rest des Codes übereinzustimmen, einen Test wie den folgenden verwenden:

if (variable == TRUE)
{
   ...
}

anstatt:

if (variable)
{
   ...
}

0

Ich benutze lieber

#define FALSE (0!=0) 
#define TRUE  (0==0)

oder direkt im Code

if (flag == (0==0)) { ... }

Der Compiler wird sich darum kümmern. Ich benutze viele Sprachen und es stört mich sehr, dass ich daran denken muss, dass FALSE 0 ist. aber wenn ich muss, denke ich normalerweise an diese String-Schleife

do { ... } while (*ptr);

und das lässt mich sehen, dass FALSE 0 ist

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.