it-swarm-eu.dev

Warum ist 0 falsch?

Diese Frage mag dumm klingen, aber warum wird 0 Zu false ausgewertet und jeder andere [ganzzahlige] Wert zu true ist in den meisten Programmiersprachen?

Zeichenfolgenvergleich

Da die Frage etwas zu einfach erscheint, werde ich mich etwas näher erläutern: Zunächst mag es jedem Programmierer klar erscheinen, aber warum sollte es keine Programmiersprache geben - es kann tatsächlich eine geben, aber keine Ich habe verwendet - wobei 0 Zu true und alle anderen [Ganzzahl] -Werte zu false ausgewertet werden? Diese eine Bemerkung mag zufällig erscheinen, aber ich habe einige Beispiele, bei denen es eine gute Idee gewesen sein könnte. Nehmen wir zunächst das Beispiel eines Drei-Wege-Vergleichs von Zeichenfolgen. Als Beispiel nehme ich Cs strcmp: Jeder Programmierer, der C als seine erste Sprache versucht, könnte versucht sein, den folgenden Code zu schreiben:

if (strcmp(str1, str2)) { // Do something... }

Da strcmp0 Zurückgibt, was bei gleichen Zeichenfolgen zu false führt, schlägt das, was der anfängliche Programmierer versucht hat, kläglich fehl und er versteht im Allgemeinen zunächst nicht, warum. Hätte 0 Stattdessen true ausgewertet, hätte diese Funktion in ihrem einfachsten Ausdruck - dem oben genannten - beim Vergleich auf Gleichheit und den richtigen Überprüfungen für -1 Und verwendet werden können 1 Wäre nur bei Bedarf durchgeführt worden. Wir hätten den Rückgabetyp die meiste Zeit als bool betrachtet (in unseren Augen meine ich).

Lassen Sie uns außerdem einen neuen Typ einführen, sign, der nur die Werte -1, 0 Und 1 Nimmt. Das kann ziemlich praktisch sein. Stellen Sie sich vor, es gibt einen Raumschiffoperator in C++ und wir wollen ihn für std::string (Nun, es gibt bereits die Funktion compare, aber der Raumschiffoperator macht mehr Spaß) . Die Erklärung wäre derzeit die folgende:

sign operator<=>(const std::string& lhs, const std::string& rhs);

Wäre 0 Zu true ausgewertet worden, würde der Raumschiffoperator nicht einmal existieren, und wir hätten operator== So deklarieren können:

sign operator==(const std::string& lhs, const std::string& rhs);

Dieser operator== Hätte sofort einen Drei-Wege-Vergleich durchgeführt und könnte weiterhin verwendet werden, um die folgende Überprüfung durchzuführen, während bei Bedarf weiterhin überprüft werden kann, welche Zeichenfolge der anderen lexikografisch überlegen ist:

if (str1 == str2) { // Do something... }

Alte Fehlerbehandlung

Wir haben jetzt Ausnahmen, daher gilt dieser Teil nur für die alten Sprachen, in denen es so etwas nicht gibt (z. B. C). Wenn wir uns die Standardbibliothek von C (und auch die von POSIX) ansehen, können wir sicher sehen, dass maaaaany-Funktionen bei Erfolg 0 Zurückgeben und ansonsten eine ganze Zahl. Ich habe leider einige Leute gesehen, die solche Dinge taten:

#define TRUE 0
// ...
if (some_function() == TRUE)
{
    // Here, TRUE would mean success...
    // Do something
}

Wenn wir darüber nachdenken, wie wir beim Programmieren denken, haben wir oft das folgende Argumentationsmuster:

Do something
Did it work?
Yes ->
    That's ok, one case to handle
No ->
    Why? Many cases to handle

Wenn wir noch einmal darüber nachdenken, wäre es sinnvoll gewesen, den einzigen neutralen Wert 0 Auf yes zu setzen (und so funktionieren die Funktionen von C), während alle anderen Werte vorhanden sein können um die vielen Fälle von no zu lösen. In allen mir bekannten Programmiersprachen (außer vielleicht einigen experimentellen esotherischen Sprachen) wird yes in einem false -Zustand zu if ausgewertet, während alle no Fälle werden mit true bewertet. Es gibt viele Situationen, in denen "es funktioniert" einen Fall darstellt, während "es funktioniert nicht" viele wahrscheinliche Ursachen darstellt. Wenn wir so denken, wäre es viel sinnvoller gewesen, 0 Mit true und den Rest mit false zu bewerten.

Fazit

Meine Schlussfolgerung ist im Wesentlichen meine ursprüngliche Frage: Warum haben wir Sprachen entworfen, in denen 0false und die anderen Werte true sind, unter Berücksichtigung meiner wenigen obigen Beispiele und vielleicht einiger weiterer Ich habe nicht daran gedacht?

Follow-up: Es ist schön zu sehen, dass es viele Antworten mit vielen Ideen und so viele mögliche Gründe dafür gibt. Ich finde es toll, wie leidenschaftlich du darüber zu sein scheinst. Ich habe diese Frage ursprünglich aus Langeweile gestellt, aber da Sie so leidenschaftlich erscheinen, habe ich mich entschlossen, ein wenig weiter zu gehen und nach der Begründung für die boolesche Wahl für 0 und 1 auf Math.SE zu fragen: )

119
Morwenn

0 ist false, da beide Nullelemente gemeinsam sind semirings . Obwohl es sich um unterschiedliche Datentypen handelt, ist es intuitiv sinnvoll, zwischen ihnen zu konvertieren, da sie zu isomorphen algebraischen Strukturen gehören.

  • 0 ist die Identität für die Addition und Null für die Multiplikation. Dies gilt für ganze Zahlen und Rationalen, aber nicht IEEE-754-Gleitkommazahlen: 0.0 * NaN = NaN und 0.0 * Infinity = NaN.

  • false ist die Identität für Boolean xor (⊻) und Null für Boolean und (∧). Wenn Boolesche Werte als {0, 1} dargestellt werden - die Menge der Ganzzahlen Modulo 2 -, können Sie sich ⊻ als Addition ohne Übertrag und ∧ als Multiplikation vorstellen.

  • "" und [] sind Identität für die Verkettung, aber es gibt mehrere Operationen, für die sie als Null sinnvoll sind. Wiederholung ist eine, aber Wiederholung und Verkettung verteilen sich nicht, sodass diese Operationen kein Semiring bilden.

Solche impliziten Konvertierungen sind in kleinen Programmen hilfreich, können jedoch in großen Programmen das Nachdenken über Programme erschweren. Nur einer der vielen Kompromisse beim Sprachdesign.

103
Jon Purdy

Weil die Mathematik funktioniert.

FALSE OR TRUE is TRUE, because 0 | 1 is 1.

... insert many other examples here.

Traditionell haben C-Programme Bedingungen wie

if (someFunctionReturningANumber())

eher, als

if (someFunctionReturningANumber() != 0)

weil das Konzept, dass Null gleich falsch ist, gut verstanden ist.

75
Robert Harvey

Wie andere gesagt haben, stand die Mathematik an erster Stelle. Aus diesem Grund ist 0 false und 1 true.

Über welche Mathematik sprechen wir? Boolesche Algebren die aus der Mitte des 19. Jahrhunderts stammen, lange bevor digitale Computer hinzukamen.

Man könnte auch sagen, dass die Konvention aus Aussagenlogik hervorgegangen ist, die sogar älter als boolesche Algebren ist. Dies ist die Formalisierung vieler logischer Ergebnisse, die Programmierer kennen und lieben (false || x entspricht x, true && x entspricht x und so weiter).

Grundsätzlich sprechen wir über Arithmetik an einer Menge mit zwei Elementen. Denken Sie daran, binär zu zählen. Boolesche Algebren sind der Ursprung dieses Konzepts und seine theoretische Grundlage. Die Konventionen von Sprachen wie C sind nur eine einfache Anwendung.

39
joshin4colours

Ich dachte, das hat mit der "Vererbung" von der Elektronik und auch der Booleschen Algebra zu tun, wo

  • 0 = off, negative, no, false
  • 1 = on, positive, yes, true

strcmp gibt 0 zurück, wenn die Zeichenfolgen gleich sind, was mit seiner Implementierung zu tun hat, da tatsächlich der "Abstand" zwischen den beiden Zeichenfolgen berechnet wird. Dass 0 auch als falsch angesehen wird, ist nur ein Zufall.

Rückgabe von bei Erfolg ist sinnvoll, da 0 in diesem Fall bedeutet, dass kein Fehler vorliegt und jede andere Zahl ein Fehler wäre Code. Die Verwendung einer anderen Zahl für den Erfolg ist weniger sinnvoll, da Sie nur einen einzigen Erfolgscode haben, während Sie mehrere Fehlercodes haben können. Sie verwenden "Hat es funktioniert?" als wenn der if-Anweisungsausdruck und sagen Sie 0 = yes sinnvoller wäre, aber der Ausdruck ist korrekter "Ist etwas schief gelaufen?" und dann sehen Sie, dass 0 = nein sehr viel Sinn macht. In Gedanken an false/true macht hier keinen Sinn, da es eigentlich no error code/error code.

27
Svish

Wie in dieser Artikel erläutert, sollten die Werte false und true nicht mit den ganzen Zahlen 0 und 1 verwechselt werden, sondern können mit den Elementen des Galois-Feldes identifiziert werden (endliches Feld) zweier Elemente (siehe hier ).

Ein Feld ist eine Menge mit zwei Operationen, die bestimmte Axiome erfüllen.

Die Symbole 0 und 1 werden üblicherweise verwendet, um die additiven und multiplikativen Identitäten eines Feldes zu bezeichnen, da die reellen Zahlen auch ein Feld (aber kein endliches) sind, dessen Identitäten die Zahlen 0 und 1 sind.

Die additive Identität ist das Element 0 des Feldes, so dass für alle x:

x + 0 = 0 + x = x

und die multiplikative Identität ist das Element 1 des Feldes, so dass für alle x:

x * 1 = 1 * x = x

Das endliche Feld zweier Elemente hat nur diese beiden Elemente, nämlich die additive Identität 0 (oder false) und die multiplikative Identität 1 (oder true). Die beiden Operationen dieses Feldes sind das logische XOR (+) und das logische UND (*).

Hinweis. Wenn Sie die Operationen umdrehen (XOR ist die Multiplikation und AND ist die Addition), ist die Multiplikation nicht über die Addition verteilt und Sie haben keine Feld nicht mehr. In einem solchen Fall haben Sie keinen Grund, die beiden Elemente 0 und 1 (in beliebiger Reihenfolge) aufzurufen. Beachten Sie auch, dass Sie die Operation OR anstelle von XOR nicht auswählen können: Unabhängig davon, wie Sie OR/AND als Addition/Multiplikation interpretieren, ist die resultierende Struktur keine Feld (nicht alle inversen Elemente existieren gemäß den Feldaxiomen).

Zu den C-Funktionen:

  • Viele Funktionen geben eine Ganzzahl zurück, die ein Fehlercode ist. 0 bedeutet KEIN FEHLER.
  • Intuitiv berechnet die Funktion strcmp die Differenz zwischen zwei Zeichenfolgen. 0 bedeutet, dass es keinen Unterschied zwischen zwei Zeichenfolgen gibt, d. H. Dass zwei Zeichenfolgen gleich sind.

Die obigen intuitiven Erklärungen können helfen, sich an die Interpretation der Rückgabewerte zu erinnern, aber es ist noch einfacher, nur die Bibliotheksdokumentation zu überprüfen.

18
Giorgio

Sie sollten berücksichtigen, dass alternative Systeme auch akzeptable Entwurfsentscheidungen sein können.

Shells: 0 Exit Status ist wahr, ungleich Null ist falsch

Das Beispiel von Shells, die einen 0-Exit-Status als wahr behandeln, wurde bereits erwähnt.

$ ( exit 0 ) && echo "0 is true" || echo "0 is false"
0 is true
$ ( exit 1 ) && echo "1 is true" || echo "1 is false"
1 is false

Das Grundprinzip dort ist, dass es einen Weg gibt, um erfolgreich zu sein, aber viele Wege, um zu scheitern. Daher ist es pragmatisch, 0 als speziellen Wert zu verwenden, der "keine Fehler" bedeutet.

Ruby: 0 ist wie jede andere Zahl

Unter den "normalen" Programmiersprachen gibt es einige Ausreißer wie Ruby, die 0 als echten Wert behandeln.

$ irb
irb(main):001:0> 0 ? '0 is true' : '0 is false'
=> "0 is true"

Das Begründung ist, dass nur false und nil falsch sein sollten. Für viele Ruby Anfänger) ist es ein Gotcha. In einigen Fällen ist es jedoch schön, dass 0 wie jede andere Zahl behandelt wird.

irb(main):002:0> (pos = 'axe' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "Found x at position 1"
irb(main):003:0> (pos = 'xyz' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "Found x at position 0"
irb(main):004:0> (pos = 'abc' =~ /x/) ? "Found x at position #{pos}" : "x not found"
=> "x not found"

Ein solches System funktioniert jedoch nur in einer Sprache, die Boolesche Werte als separaten Typ von Zahlen unterscheiden kann. In den früheren Tagen des Rechnens hatten Programmierer, die mit Assemblersprache oder roher Maschinensprache arbeiteten, keinen solchen Luxus. Es ist wahrscheinlich nur natürlich, 0 als "leeren" Zustand zu behandeln und ein Bit als Flag auf 1 zu setzen, wenn der Code feststellt, dass etwas passiert ist. In der Erweiterung entwickelte sich die Konvention, dass Null als falsch behandelt wurde und Nicht-Null-Werte als wahr behandelt wurden. Das muss aber nicht so sein.

Java: Zahlen können überhaupt nicht als Boolesche Werte behandelt werden

In Java sind true und false die einzigen booleschen Werte. Zahlen sind keine Booleschen Werte und können nicht einmal in Boolesche Werte umgewandelt werden ( Java Language Specification, Abschnitt 4.2.2 ):

Es gibt keine Umwandlungen zwischen Integraltypen und dem Typ boolean.

Diese Regel vermeidet nur die Frage insgesamt - alle booleschen Ausdrücke müssen explizit in den Code geschrieben werden.

14
200_success

Bevor wir uns mit dem allgemeinen Fall befassen, können wir Ihre Gegenbeispiele diskutieren.

Stringvergleiche

Das gleiche gilt eigentlich für viele Arten von Vergleichen. Solche Vergleiche berechnen einen Abstand zwischen zwei Objekten. Wenn die Objekte gleich sind, ist der Abstand minimal. Wenn der "Vergleich erfolgreich" ist, ist der Wert 0. Aber tatsächlich ist der Rückgabewert von strcmp kein Boolescher Wert ist eine Entfernung, und das, was unbewusste Programmierer einfängt, die if (strcmp(...)) do_when_equal() else do_when_not_equal() tun.

In C++ könnten wir strcmp neu gestalten, um ein Distance Objekt zurückzugeben, das operator bool() überschreibt, um true zurückzugeben, wenn 0 (aber Sie würden dann von einer anderen Reihe von Problemen gebissen werden). . Oder in einfachem C haben Sie einfach eine streq -Funktion, die 1 zurückgibt, wenn die Zeichenfolgen gleich sind, und andernfalls 0.

API-Aufrufe/Programm-Exit-Code

Hier geht es Ihnen um den Grund, warum etwas schief gelaufen ist, da dies die Fehlerentscheidungen in die Höhe treibt. Wenn die Dinge erfolgreich sind, möchten Sie nichts Besonderes wissen - Ihre Absicht wird verwirklicht. Der Rückgabewert muss daher diese Information vermitteln. Es ist kein Boolescher Wert, sondern ein Fehlercode. Der spezielle Fehlerwert 0 bedeutet "kein Fehler". Der Rest des Bereichs stellt lokal bedeutsame Fehler dar, mit denen Sie sich befassen müssen (einschließlich 1, was häufig "nicht spezifizierter Fehler" bedeutet).

Allgemeiner Fall

Dies lässt uns die Frage offen: Warum werden boolesche Werte True und False üblicherweise mit 1 bzw. 0 dargestellt?

Nun, neben dem subjektiven Argument "es fühlt sich so besser an" sind hier einige Gründe (auch subjektiv), die ich mir vorstellen kann:

  • stromkreisanalogie. Der Strom ist für 1s EIN und für 0s AUS. Ich mag es, (1, Ja, Richtig, Ein) zusammen und (0, Nein, Falsch, Aus) zusammen zu haben, anstatt eine andere Mischung

  • speicherinitialisierungen. Wenn ich memset(0) eine Reihe von Variablen (seien es Ints, Floats, Bools), möchte ich, dass ihr Wert den konservativsten Annahmen entspricht. Z.B. Meine Summe ist anfänglich 0, das Prädikat ist False usw.

Vielleicht hängen all diese Gründe mit meiner Ausbildung zusammen - wenn mir von Anfang an beigebracht worden wäre, 0 mit True zu assoziieren, würde ich den umgekehrten Weg gehen.

8
user44761

Aus einer übergeordneten Perspektive sprechen Sie von drei ganz unterschiedlichen Datentypen:

  1. Ein Boolescher Wert. Die mathematische Konvention in Boolesche Algebra lautet 0 für false und 1 für true, daher ist es sinnvoll, dieser Konvention zu folgen. Ich denke, dieser Weg macht auch intuitiv mehr Sinn.

  2. Das Ergebnis des Vergleichs. Dies hat drei Werte: <, = und > (beachten Sie, dass keiner von ihnen true ist). Für sie ist es sinnvoll, die Werte -1, 0 bzw. 1 (oder allgemeiner einen negativen Wert, Null und einen positiven Wert) zu verwenden.

    Wenn Sie auf Gleichheit prüfen möchten und nur eine Funktion haben, die einen allgemeinen Vergleich durchführt, sollten Sie dies meiner Meinung nach explizit machen, indem Sie etwas wie strcmp(str1, str2) == 0 verwenden. Ich finde die Verwendung von ! in dieser Situation verwirrend, da ein nicht-boolescher Wert so behandelt wird, als wäre er ein boolescher Wert.

    Denken Sie auch daran, dass Vergleich und Gleichheit nicht dasselbe sein müssen. Wenn Sie beispielsweise Personen nach ihrem Geburtsdatum bestellen, sollte Compare(me, myTwin)0 zurückgeben, Equals(me, myTwin) jedoch false.

  3. Der Erfolg oder Misserfolg einer Funktion, möglicherweise auch mit Details zu diesem Erfolg oder Misserfolg. Wenn Sie über Windows sprechen, heißt dieser Typ HRESULT und ein Wert ungleich Null bedeutet nicht unbedingt einen Fehler. Tatsächlich zeigt ein negativer Wert einen Fehler und einen nicht negativen Erfolg an. Der Erfolgswert ist sehr oft S_OK = 0, kann aber auch beispielsweise S_FALSE = 1 oder andere Werte sein.

Die Verwirrung ergibt sich aus der Tatsache, dass drei logisch sehr unterschiedliche Datentypen in C und einigen anderen Sprachen tatsächlich als ein einziger Datentyp (eine Ganzzahl) dargestellt werden und dass Sie eine Ganzzahl in einer Bedingung verwenden können. Ich halte es jedoch nicht für sinnvoll, Boolesche Werte neu zu definieren, um die Verwendung einiger nicht-Boolescher Typen unter Bedingungen zu vereinfachen.

Betrachten Sie auch einen anderen Typ, der häufig in einer Bedingung in C verwendet wird: einen Zeiger. Dort ist es natürlich, einen NULL- Zeiger (der als 0 dargestellt wird) als false zu behandeln. Wenn Sie also Ihrem Vorschlag folgen, wird das Arbeiten mit Zeigern auch schwieriger. (Ich persönlich bevorzuge es jedoch, Zeiger explizit mit NULL zu vergleichen, anstatt sie als Boolesche Werte zu behandeln.)

6
svick

Null kann falsch sein, da die meisten CPUs ein ZERO-Flag haben, das zum Verzweigen verwendet werden kann. Es speichert eine Vergleichsoperation.

Mal sehen warum.

Einige Pseudocodes, da das Publikum wahrscheinlich nicht Assembly liest

c-source einfache Schleifenaufrufe wibbeln 10 Mal

for (int foo =10; foo>0; foo-- ) /* down count loop is shorter */
{  
   wibble();
}

einige tun so, als ob die Versammlung dafür wäre

0x1000 ld a 0x0a      'foo=10
0x1002 call 0x1234    'call wibble()
0x1005 dec a          'foo--
0x1006 jrnz -0x06      'jump back to 0x1000 if not zero
0x1008  

c- Quelle Eine weitere einfache Schleife ruft 10 Mal Wibble auf

for (int foo =0; foo<10; foo-- ) /* up count loop is longer  */
{  
   wibble();
}

einige tun so, als ob sie sich für diesen Fall versammelt hätten

0x1000 ld a 0x00      'foo=0
0x1002 call 0x1234    'call wibble()
0x1005 dec a          'foo--
0x1006 cmp 0x0a       'compare foo to 10 ( like a subtract but we throw the result away)
0x1008 jrns -0x08      'jump back to 0x1000 if compare was negative
0x100a  

etwas mehr c Quelle

int foo=10;
if ( foo ) wibble()

und die Versammlung

0x1000 ld a 0x10
0x1002 jz 0x3
0x1004 call 0x1234
0x1007  

sehen, wie kurz das ist?

etwas mehr c Quelle

int foo=10;
if ( foo==0 ) wibble()

und die Assembly (nehmen wir einen geringfügig intelligenten Compiler an, der == 0 ohne Vergleich ersetzen kann)

0x1000 ld a 0x10
0x1002 jz 0x3
0x1004 call 0x1234
0x1007  

Versuchen wir nun eine Konvention von true = 1

etwas mehr c source #define TRUE 1 int foo = TRUE; if (foo == TRUE) wibble ()

und die Versammlung

0x1000 ld a 0x1
0x1002 cmp a 0x01
0x1004 jz 0x3
0x1006 call 0x1234
0x1009 

sehen, wie kurz der Fall mit ungleich Null wahr ist?

Wirklich frühe CPUs hatten kleine Sätze von Flags am Akkumulator angebracht.

Um zu überprüfen, ob a> b oder a = b ist, wird im Allgemeinen eine Vergleichsanweisung verwendet.

  • Es sei denn, B ist entweder NULL - in diesem Fall wird das ZERO-Flag gesetzt. Implementiert als einfaches logisches NOR oder alle Bits im Akkumulator.
  • Oder NEGATIV, bei dem nur das "Vorzeichenbit" verwendet wird, d. H. Das höchstwertige Bit des Akkumulators, wenn Sie die Zweierkomplementarithmetik verwenden. (Meistens tun wir das)

Lassen Sie uns dies wiederholen. Bei einigen älteren CPUs mussten Sie keine Vergleichsanweisung für einen Akku verwenden, der gleich NULL ist, oder für einen Akku, der kleiner als Null ist.

Sehen Sie jetzt, warum Null falsch sein könnte?

Bitte beachten Sie, dass dies Pseudo-Code ist und kein wirklicher Befehlssatz so aussieht. Wenn Sie Assembly kennen, wissen Sie, dass ich die Dinge hier stark vereinfache. Wenn Sie etwas über das Compiler-Design wissen, mussten Sie das nicht Lesen Sie diese Antwort. Jeder, der etwas über das Abrollen von Schleifen oder die Vorhersage von Zweigen weiß, der ist in Raum 203 im Flur.

4
Tim Williscroft

Seltsamerweise ist Null nicht immer falsch.

Insbesondere definiert die Unix- und Posix-Konvention EXIT_SUCCESS Als 0 (und EXIT_FAILURE Als 1). Eigentlich ist es sogar ein Standard C-Konvention !

Für Posix-Shells und exit (2) syscalls bedeutet 0 "erfolgreich", was intuitiv mehr wahr als falsch ist.

Insbesondere möchte die Shell if, dass eine Prozessrückgabe EXIT_SUCCESS (Das ist 0) ihrem "dann" -Zweig folgt!

In Schema (aber nicht in Common LISP oder in SCHMELZE ) sind 0 und Null (dh () In Schema) wahr, da die einzigen falsch sind Wert ist #f

Ich stimme zu, ich picke nicht!

Es gibt viele Antworten, die darauf hindeuten, dass eine Korrespondenz zwischen 1 und true aufgrund einer mathematischen Eigenschaft erforderlich ist. Ich kann keine solche Eigenschaft finden und schlage vor, dass es sich um eine rein historische Konvention handelt.

Bei einem Feld mit zwei Elementen haben wir zwei Operationen: Addition und Multiplikation. Wir können Boolesche Operationen auf diesem Feld auf zwei Arten abbilden:

Traditionell identifizieren wir True mit 1 und False mit 0. Wir identifizieren AND mit * und XOR mit +. Somit ist OR eine sättigende Addition).

Wir könnten jedoch genauso gut True mit 0 und False mit 1 identifizieren. Dann identifizieren wir OR mit * und XNOR mit +. Somit ist AND eine sättigende Addition.

3
Neil G

C wird für die Low-Level-Programmierung in der Nähe der Hardware verwendet, einem Bereich, in dem Sie manchmal zwischen bitweisen und logischen Operationen für dieselben Daten wechseln müssen. Wenn ein numerischer Ausdruck nur zum Ausführen eines Tests in einen Booleschen Ausdruck konvertiert werden muss, wird der Code unübersichtlich.

Sie können Dinge schreiben wie:

if (modemctrl & MCTRL_CD) {
   /* carrier detect is on */
}

eher, als

if ((modemctrl & MCTRL_CD) != 0) {
    /* carrier detect is on */
}

In einem isolierten Beispiel ist es nicht so schlimm, aber das zu tun wird lästig.

Ebenso umgekehrte Operationen. Für das Ergebnis einer booleschen Operation wie eines Vergleichs ist es nützlich, nur eine 0 oder 1 zu erzeugen: Angenommen, wir möchten das dritte Bit eines Wortes basierend darauf setzen, ob modemctrl das Trägererkennungsbit hat:

flags |= ((modemctrl & MCTRL_CD) != 0) << 2;

Hier müssen wir den != 0 Haben, um das Ergebnis des biweisen & - Ausdrucks auf 0 Oder 1 Zu reduzieren, aber weil das Ergebnis nur eine ganze Zahl ist Wir müssen keine nervigen Besetzungen hinzufügen, um den Booleschen Wert weiter in eine Ganzzahl umzuwandeln.

Obwohl das moderne C jetzt einen bool -Typ hat, behält es die Gültigkeit von Code wie diesem bei, sowohl weil es eine gute Sache ist als auch wegen des massiven Bruches mit der Abwärtskompatibilität, der sonst verursacht würde.

Ein weiteres Beispiel, bei dem C glatt ist: Testen von zwei booleschen Bedingungen als Vierwegeschalter:

switch (foo << 1 | bar) {  /* foo and bar booleans are 0 or 1 */
case 0: /* !foo && !bar */
   break;
case 1: /* !foo && bar */
   break;
case 2: /* foo && !bar */
   break;
case 3: /* foo && bar */
   break;
}

Sie könnten dies dem C-Programmierer nicht kampflos nehmen!

Schließlich dient C manchmal als eine Art Assemblersprache auf hoher Ebene. In Assemblersprachen haben wir auch keine booleschen Typen. Ein boolescher Wert ist nur ein Bit oder eine Null gegenüber einem Wert ungleich Null in einem Speicherort oder Register. Eine ganzzahlige Null, eine boolesche Null und die Adresse Null werden alle in Assembler-Befehlssätzen (und möglicherweise sogar Gleitkomma-Null) auf dieselbe Weise getestet. Die Ähnlichkeit zwischen C und Assemblersprache ist nützlich, beispielsweise wenn C als Zielsprache für das Kompilieren einer anderen Sprache verwendet wird (auch einer, die stark boolesche Werte aufweist!).

3
Kaz

Ein Boolescher oder Wahrheitswert hat nur 2 Werte. Richtig und falsch.

Diese sollten nicht als ganze Zahlen, aber als Bits (0 und 1) dargestellt werden.

Zu sagen, dass eine andere Ganzzahl neben 0 oder 1 nicht falsch ist, ist eine verwirrende Aussage. Wahrheitstabellen behandeln Wahrheitswerte, keine ganzen Zahlen.

Von einem potenziellen Wahrheitswert würden -1 oder 2 alle Wahrheitstabellen und jede damit verbundene boolesche Logik brechen.

  • 0 UND -1 == ?!
  • 0 OR 2 == ?!

Die meisten Sprachen haben normalerweise den Typ boolean, der bei Umwandlung in einen Zahlentyp wie Integer false als Ganzzahlwert 0 anzeigt.

0
Jon Raynor