Gibt der C-Standard den Wahrheitswert explizit als 0 oder 1 an?

85

Wir wissen, dass alle Zahlen, die nicht gleich 0sind, wie truein C angesehen werden, also können wir schreiben:

int a = 16;

while (a--)
    printf("%d\n", a);  // prints numbers from 15 to 0

Ich habe mich jedoch gefragt, ob wahr / falsch als 1/ 0in C definiert sind , also habe ich den folgenden Code ausprobiert:

printf("True = %d, False = %d\n", (0 == 0), (0 != 0));  // prints: True = 1, False = 0

Gibt der C-Standard explizit die Wahrheitswerte von wahr und falsch als 1bzw. 0an?

Kevin Dong
quelle
3
Ich denke, diese SO-Frage ist relevant
Imran Ali
3
Ich versuche , diese unter laufen gccmit -std=c89und es ergibt sich das gleiche Ergebnis.
Kevin Dong
1
@ Blackhole, von 15 bis 0.
Arturo Torres Sánchez
6
Fast betrogen, aber über ein Jahrzehnt vor SO / SE: c-faq.com/bool/bool2.html .
dave_thompson_085
1
Dass falsch Null ist, ist Kanon, aber wahr wird allgemein als "nicht Null" angesehen. Da Programmierer das sind, was sie sind, haben wir alle aus verschiedenen Gründen 1 als "nicht Null" verwendet. Sie werden ermutigt, einem Wahren nicht zu vertrauen, um genau 1 zu sein. Während (0 == 0) in Ihrem Beispiel eins ist, könnte etwas wie (12 == 12) genauso gut den Wert 12 haben; auch wahr".
Ingenieur

Antworten:

95

Gibt der C-Standard explizit die Wahrheitswerte von trueund falseals 0bzw. 1an?

Der C - Standard definiert trueund falseals Makros in stdbool.hdem erweitern 1und 0jeweils.

C11-§7.18:

Die verbleibenden drei Makros eignen sich zur Verwendung in #ifVorverarbeitungsanweisungen. Sie sind

true

die sich auf die Ganzzahlkonstante erweitert 1,

false

die auf die Ganzzahlkonstante erweitert 0[...]

Für die Betreiber ==und !=, sagt Standard

C11-§6.5.9 / 3:

Die Operatoren ==(gleich) und !=(ungleich) sind bis auf ihre niedrigere Priorität analog zu den Vergleichsoperatoren. 108) Jeder der Operatoren gibt nach, 1ob die angegebene Beziehung wahr und 0ob sie falsch ist. Das Ergebnis hat Typ int. Für jedes Operandenpaar gilt genau eine der Beziehungen.

Haccks
quelle
20
Es scheint mir , dass die Frage nach ist 0 == 0und 0 != 0etc., die nicht der Wert von Makros.
MM
9
Ich denke, als er schrieb true, meinte er "den Wert eines echten Vergleichs" oder so etwas, nicht das Makrotrue
MM
1
@ KevinDong; Ja, der C99-Entwurf enthält einen ähnlichen Absatz.
Haccks
1
@haccks: Sie können ohne zu zögern "identisch" darüber sagen. Ich habe gerade Ihr Zitat aufgegriffen, da ich zu faul war, um nach Absätzen nachzuschlagen, da ich mich bei Bedarf auf c99 beziehe. Und ich konnte es finden, indem ich es einfach über ctrl+ suchte f;)
dhein
2
@MooingDuck: NaN == NaNist falsch undNaN != NaN ist wahr. Es gibt kein Problem mit dieser Aussage.
Kennytm
51

Es ist in C11 nicht explizit angegeben. Alle Operationen auf Sprachebene geben 1 als wahr zurück (und akzeptieren alle ungleich Null einschließlich NaN als wahr).

  • Wenn Sie sich Sorgen machen _Bool, muss true 1 sein, da der Standard nur 0 und 1 vorschreibt (§6.2.5 / 2).
  • Auch im <stdbool.h>Makro trueerweitert sich zu 1(§7.18 / 3)
  • ==, !=, <, >, <=Und das >=Rück 0 oder 1 (§6.5.8 / 6, §6.5.9 / 3).
  • !, &&Und das ||Rück 0 oder 1 (§6.5.3.3 / 5, §6.5.13 / 3, §6.5.14 / 3)
  • defined erweitert auf 0 oder 1 (§6.10.1 / 1)

Aber alles Standardbibliotheksfunktionenislower sagen zB einfach "ungleich Null" für die Wahrheit (z. B. §7.4.1 / 1, §7.17.5.1 / 3, §7.30.2.1 / 1, §7.30.2.2.1 / 4).


§6.2.5 / 2 : Ein als Typ deklariertes Objekt _Boolist groß genug, um die Werte 0 und 1 zu speichern.

§6.5.5.3 / 5 : Das Ergebnis des logischen Negationsoperators !ist 0, wenn der Wert seines Operanden ungleich 0 ist, 1, wenn der Wert seines Operanden gleich 0 ist.…

§6.5.8 / 6 : Jeder der Operatoren <(kleiner als), >(größer als),<= (kleiner als oder gleich) und >=(größer als oder gleich) muss 1 ergeben, wenn die angegebene Beziehung wahr ist, und 0, wenn dies der Fall ist ist falsch. 107)…

§6.5.9 / 3 : Die Operatoren ==(gleich) und !=(ungleich) sind bis auf ihre niedrigere Priorität analog zu den Vergleichsoperatoren.108) Jeder der Operatoren ergibt 1, wenn die angegebene Beziehung wahr ist, und 0, wenn dies der Fall ist falsch. …

§6.5.13 / 3 : Der &&Operator muss 1 ergeben, wenn beide Operanden ungleich 0 sind; …

§6.5.14 / 3 : Der ||Operator muss 1 ergeben, wenn einer seiner Operanden ungleich 0 ist; …

§6.10.1 / 1 :… kann unäre Operatorausdrücke der Form - defined identifier- oder - defined ( identifier )- enthalten, die mit 1 bewertet werden, wenn…

§7.4.1 (Zeichenklassifizierungsfunktionen) / 1 : Die Funktionen in diesem Unterabschnitt geben genau dann einen Wert ungleich Null (wahr) zurück, wenn…

§7.18 / 3 : Die restlichen drei Makros sind zur Verwendung in geeignet#if Vorverarbeitungsanweisungen. Sie sind - true- die sich auf die ganzzahlige Konstante 1 ausdehnen,…

§7.17.5.1 / 3 : Dieatomic_is_lock_free generische Funktion gibt genau dann einen ungleich Null (true) zurück, wenn die Operationen des Objekts sind. …

§7.30.2.1 (Funktionen zur Klassifizierung breiter Zeichen) / 1 : Die Funktionen in diesem Unterabschnitt geben genau dann einen ungleich Null (wahr) zurück, wenn…

§7.30.2.2.1 / 4 : Die iswctypeFunktion gibt genau dann einen Wert ungleich Null (true) zurück, wenn…

kennytm
quelle
22

Es gibt zwei Bereiche des Standards, die Sie beachten müssen, wenn Sie mit Booleschen Werten arbeiten (womit ich eher wahre / falsche Werte als das spezifische C meine bool/_Bool Typ ) in C .

Das erste hat mit dem Ergebnis von Ausdrücken zu tun und kann in verschiedenen Teilen von C11 6.5 Expressions(z. B. relationale und Gleichheitsoperatoren) gefunden werden. Die Quintessenz ist, dass jedes Mal, wenn ein Boolescher Wert von einem Ausdruck generiert wird, ...

... ergibt 1, wenn die angegebene Beziehung wahr ist, und 0, wenn sie falsch ist. Das Ergebnis hat den Typ int.

Ja, das Ergebnis eines Booleschen generierenden Ausdrucks ist eins für wahr oder null für falsch. Dies entspricht dem, was Sie in stdbool.hden Standardmakros trueund findenfalse auf die gleiche Weise definiert sind.

Beachten Sie jedoch, dass nach dem Robustheitsprinzip "Seien Sie konservativ in dem, was Sie senden, liberal in dem, was Sie akzeptieren" die Interpretation von ganzen Zahlen im booleschen Kontext etwas entspannter ist.

Wiederum sehen Sie aus verschiedenen Teilen der 6.5Sprache:

Der ||Operator muss 1 ergeben, wenn einer seiner Operanden ungleich 0 ist. Andernfalls ergibt sich 0. Das Ergebnis hat den Typ int.

Daraus (und aus anderen Teilen) geht hervor, dass Null als falsch angesehen wird und jeder andere Wert wahr ist.


Abgesehen davon erscheint die Sprache, die angibt, welche Werte für die Erzeugung und Interpretation von Booleschen Werten verwendet werden, auch in C99 und C89, sodass es sie schon seit geraumer Zeit gibt. Sogar K & R (ANSI-C zweite Ausgabe und die erste Ausgabe) spezifizierte dies mit Textsegmenten wie:

Relationale Ausdrücke wie i > jund logische Ausdrücke, die durch &&und verbunden ||sind, haben einen Wert1 wenn sie wahr sind, und0 wenn sie falsch sind.

Im Testteil von if,while ,for usw, „true“ bedeutet nur „Nicht-Null“.

Das && Operator ... gibt 1 zurück, wenn beide Operanden ungleich Null sind, andernfalls 0.

Das || Operator ... gibt 1 zurück, wenn einer seiner Operanden ungleich Null ist, andernfalls 0.

Die Makros in werden stdbool.hauch in C99 angezeigt, jedoch nicht in C89 oder K & R, da diese Header-Datei zu diesem Zeitpunkt noch nicht vorhanden war.

paxdiablo
quelle
2
beachten Sie, dass ||, ==, !=usw. Ausbeute int, kein boolean Typ
MM
2
Ich stimme diese Frage für die richtige. Für mich geht es auch um die Vergleichsoperatoren und nicht um die Makros.
Ckruczek
„Im Testteil if, while, forusw,‚true‘bedeutet nur‚Nicht-Null‘.“ Dies ist der herausragende Teil der Antwort und meiner Meinung nach eine unglückliche Entscheidung von Dennis Ritchie von vor langer Zeit. Jeder, der Funktionen geschrieben hat, die Fehlercodes als Rückgabewert zurückgeben, #define noErr 0und jeder Fehlercode ungleich Null, ist ein Fehler. Und dann ist das Problem, dass die Einfachheit und Schönheit von if ( ready_to_do_something() ){do_something();} nicht funktioniert. Es muss sein: if ( !not_ready_to_do_something() ){do_something();}"Es gibt viele Unwahrheiten, aber nur eine Wahrheit." WAHR sollte 0 sein.
Robert Bristow-Johnson
Wie haben die ersten Entwürfe von C-Regeln aus Neugier das Verhalten von "&&" und "||" spezifiziert? in dem Fall, in dem die Operanden andere Werte als 0 oder 1 hatten? Der von Ihnen zitierte Text enthält "logische Ausdrücke", die durch && und || verbunden sind. Was ist jedoch, wenn diese Operatoren andere Dinge als logische Ausdrücke verbinden?
Superkatze
1
@ Sdenham, ja. In der frühesten Ausgabe von K & R I (erste Ausgabe, Auflage 14, eine so früh, dass die Hardwareeigenschaften von vier typischen Maschinen, PDP-11, Honeywell-6000, IBM-370 und Interdata-8/32, erwähnt werden), A.7.6/7/10/11(relational / gleichheit / logisch-und / logisch-oder) alle geben an, dass es als Ergebnis 0 oder 1 gibt. Habe die Antwort aktualisiert, um das einzuschließen.
Paxdiablo
9

Sie vermischen viele verschiedene Dinge: Steueranweisungen, Operatoren und Boolesche Typen. Jeder hat seine eigenen Regeln.

ifSteueranweisungen funktionieren wie zum Beispiel die Anweisung C11 6.4.8.1:

In beiden Formen wird die erste Unteranweisung ausgeführt, wenn der Ausdruck ungleich 0 ist.

while, for Usw. die gleiche Regel haben. Dies hat nichts mit "wahr" oder "falsch" zu tun.

Operatoren, die angeblich ein boolesches Ergebnis intliefern, liefern tatsächlich ein Ergebnis mit dem Wert 1 oder 0. Zum Beispiel die Gleichheitsoperatoren C11 6.5.9:

Jeder der Operatoren ergibt 1, wenn die angegebene Beziehung wahr ist, und 0, wenn sie falsch ist

All dies ist darauf zurückzuführen, dass C bis zum Jahr 1999 keinen booleschen Typ hatte, und selbst wenn es einen bekam, wurden die oben genannten Regeln nicht geändert. Im Gegensatz zu den meisten anderen Programmiersprachen, in denen Anweisungen und Operatoren einen booleschen Typ ergeben (wie C ++ und Java), ergeben sie nur einen intmit dem Wert Null oder nicht Null. Beispielsweise,sizeof(1==1) wird 4 in C aber 1 in C ++ geben.

Der tatsächliche boolesche Typ in C wird benannt _Boolund erfordert einen modernen Compiler. Der Header stdbool.hdefinieren Makros bool, trueund false, die zu erweitern _Bool, 1und die 0jeweils (für die Kompatibilität mit C ++).


Es wird jedoch als gute Programmierpraxis angesehen, Steueranweisungen und Operatoren so zu behandeln, als ob sie tatsächlich einen booleschen Typ benötigen / ergeben. Bestimmte Codierungsstandards wie MISRA-C empfehlen eine solche Vorgehensweise. Das ist:

if(ptr == NULL)statt if(ptr).

if((data & mask) != 0) anstatt if(data & mask) .

Ziel eines solchen Stils ist es, die Typensicherheit mithilfe statischer Analysewerkzeuge zu erhöhen, wodurch wiederum Fehler reduziert werden. Dieser Stil ist wahrscheinlich nur dann sinnvoll, wenn Sie statische Analysegeräte verwenden. In einigen Fällen führt dies beispielsweise zu besser lesbarem, selbstdokumentierendem Code

if(c == '\0') 

Gut, die Absicht ist klar, der Code ist selbstdokumentierend.

gegen

if(c) 

Schlecht. Könnte alles bedeuten, und wir müssen nach dem Typ suchen c, um den Code zu verstehen. Ist es eine ganze Zahl, ein Zeiger oder ein Zeichen?

Lundin
quelle
1
sizeof(bool)ist implementierungsspezifisch in C ++. Siehe stackoverflow.com/questions/4897844/is-sizeofbool-defined .
David Hammen
@DavidHammen Ebenso wie sizeof (0 == 0) auch implementierungsdefiniert ist. Es ist nur ein Beispiel.
Lundin
Ich dachte, C hat die Regeln für Boolesche Typen geändert. Andere Arten von uintN-Typen (einschließlich der "Bit" -Typen vieler älterer Compiler) speichern die niedrigeren N Bits eines Werts und ignorieren alle höheren Bits, während die neuen Booleschen Typen effektiv "oder" alle Bits zusammen ".
Supercat
1
Sollte das sein if(ptr != NULL)oder vielleicht if(!ptr)?
Mathieu K.
1
if(c == '\0')eignet sich für den besonders häufigen Anfängerfehler beim Codieren if(c = '\0'), deshalb vermeide ich ihn. Einverstanden, if(c)ist schlecht ... es sollte zum Beispiel seinif(valveIsOpen)
aja
4

Ich habe in vielen Sprachen programmiert. Ich habe gesehen, dass je nach Sprache wahr 1 oder -1 ist. Die Logik hinter dem wahren Sein 1 war, dass ein Bit entweder eine 0 oder 1 war. Die Logik hinter dem wahren Sein -1 war, dass das! Betreiber war eine Ergänzung. Es änderte alle Einsen in Nullen und alle Nullen in Einsen in einem Int. Also, für ein int ,! 0 = -1 und! (- 1) = 0. Dies hat mich so gestolpert, dass ich etwas nicht mit == wahr vergleiche, sondern mit! = Falsch. Auf diese Weise funktioniert mein Programmierstil in jeder Sprache. Meine Antwort ist also, sich keine Sorgen zu machen, sondern so zu programmieren, dass Ihr Code in beiden Fällen korrekt funktioniert.

Russell Hankins
quelle
wie kann ! Ändern Sie alle Nullen in Einsen und produzieren Sie immer noch 0 für! 5?
Codeshot
@codeshot Es kann nicht. Aber der Punkt, den er macht, ist, dass nicht alle Sprachen den Operanden von behandeln! als Boolescher Wert. Einige behandeln! als C's ~ - das heißt, eine bitweise Ergänzung. In diesem Fall muss zur Bestimmung des resultierenden Werts zunächst der Typ der Variablen bekannt sein. Daher wäre! (Uint32_t) 5 4.294.967.290. Aber! 0 ist immer noch 4.294.967.295 und 4.294.967.295 ist wahr.
Pegasus Epsilon
1

Diese Antwort muss etwas genauer betrachtet werden.

Die eigentliche Definition in C ++ ist, dass alles, was nicht 0 ist, als wahr behandelt wird. Warum ist das relevant? Da C ++ nicht weiß, was eine Ganzzahl ist, indem wir darüber nachdenken - wir schaffen diese Bedeutung, alles, was sie enthält, ist die Shell und die Regeln für das, was das bedeutet. Es weiß jedoch, was Bits sind, was eine ganze Zahl ausmacht.

1 als Ganzzahl wird lose in Bits dargestellt, beispielsweise ein 8-Bit-Int mit Vorzeichen als 0000 0001. Oft ist das, was wir visuell sehen, eine Lüge. -1 ist aufgrund der vorzeichenbehafteten Natur eine viel häufigere Art, es darzustellen von 'integer'. Ich kann wirklich nicht richtig richtig meinen, warum? Da es sich NICHT um eine Operation handelt, ist 1111 1110. Das ist ein wirklich großes Problem für einen Booleschen Wert. Wenn wir über einen Booleschen Wert sprechen, ist es nur 1 Bit - es ist wirklich einfach, 0 ist falsch und 1 ist wahr. Alle logischen Operationen gelten als trivial. Aus diesem Grund sollte '-1' für Ganzzahlen (signiert) als 'true' bezeichnet werden. 1111 1111 NOT'ed wird 0000 0000 --- die Logik gilt und wir sind gut. Unsigned Ints ist ein bisschen knifflig und wurde in der Vergangenheit viel häufiger verwendet - wobei 1 wahr bedeutet, weil es einfach ist, die Logik zu implizieren, dass '

Das ist die Erklärung. Ich sage, die hier akzeptierte Antwort ist falsch - es gibt keine klare Definition in der C / C ++ - Definition. Ein Boolescher Wert ist ein Boolescher Wert. Sie können eine Ganzzahl als Booleschen Wert behandeln. Die Tatsache, dass die Ausgabe eine Ganzzahl ist, sagt jedoch nichts über die tatsächlich ausgeführte Operation aus.

Tommy
quelle
4
Die Frage betraf C, nicht C ++.
glglgl
0

Dies geschah aufgrund der relationalen Operatoren in Ihrer printfErklärung.

Betreiber ==und Betreiber!=

Da dies (0 == 0)zutrifft, gibt es einen Wert1

wohingegen (0 != 0)dies nicht zutrifft, ergibt sich ein Wert 0.

SKD
quelle