Ich habe Definitionen in C gesehen
#define TRUE (1==1)
#define FALSE (!TRUE)
Ist das notwendig? Was ist der Vorteil gegenüber der einfachen Definition von TRUE als 1 und FALSE als 0?
Ich habe Definitionen in C gesehen
#define TRUE (1==1)
#define FALSE (!TRUE)
Ist das notwendig? Was ist der Vorteil gegenüber der einfachen Definition von TRUE als 1 und FALSE als 0?
Antworten:
Bei diesem Ansatz wird der tatsächliche boolean
Typ verwendet (und in true
und aufgelöst false
), wenn der Compiler dies unterstützt. (speziell C ++)
Es ist jedoch besser zu überprüfen, ob C ++ verwendet wird (über das __cplusplus
Makro) und tatsächlich true
und zu verwenden false
.
In einem C-Compiler entspricht dies 0
und 1
.
(Beachten Sie, dass das Entfernen der Klammern dies aufgrund der Reihenfolge der Operationen unterbricht.)
1==1
ist ein int
. (Siehe stackoverflow.com/questions/7687403/… .)
boolean
Typ?
true
oder zurück false
.
#define TRUE true
und #define FALSE false
wann immer __cplusplus
es definiert ist.
Die Antwort ist Portabilität. Die numerischen Werte von TRUE
und FALSE
sind nicht wichtig. Was ist wichtig, dass eine Aussage wie if (1 < 2)
auswertet zu if (TRUE)
und eine Erklärung wie if (1 > 2)
auswertet zu if (FALSE)
.
Zugegeben, in C wird (1 < 2)
ausgewertet 1
und (1 > 2)
ausgewertet. 0
Wie andere bereits gesagt haben, gibt es für den Compiler keinen praktischen Unterschied. Aber indem man die Compiler definieren TRUE
und FALSE
nach seinen eigenen Regeln, Sie machen ihre Bedeutung für Programmierer explizit, und Sie garantieren Konsistenz in Ihrem Programm und andere Bibliothek (die andere Bibliothek unter der Annahme folgt Standards C ... du würdest sei erstaunt).
Einige Geschichte
Einige BASICs definiert FALSE
als 0
und TRUE
als -1
. Wie viele moderne Sprachen interpretierten sie jeden Wert ungleich Null als TRUE
, aber sie bewerteten boolesche Ausdrücke, die wahr waren als -1
. Ihre NOT
Operation wurde implementiert, indem 1 hinzugefügt und das Zeichen umgedreht wurde, da dies effizient war. So wurde 'NICHT x' -(x+1)
. Ein Nebeneffekt davon ist, dass ein Wert wie5
bewertet TRUE
, aber NOT 5
bewertet -6
, was auch ist TRUE
! Es macht keinen Spaß, diese Art von Fehler zu finden.
Best Practices
Angesichts der De-facto- Regeln, als die Null interpretiert wird FALSE
und jeder Wert ungleich Null als interpretiert wird TRUE
, sollten Sie niemals boolesch aussehende Ausdrücke mit TRUE
oder vergleichenFALSE
. Beispiele:
if (thisValue == FALSE) // Don't do this!
if (thatValue == TRUE) // Or this!
if (otherValue != TRUE) // Whatever you do, don't do this!
Warum? Weil viele Programmierer die Abkürzung verwenden, int
s als bool
s zu behandeln. Sie sind nicht gleich, aber Compiler erlauben es im Allgemeinen. So ist es zum Beispiel völlig legal zu schreiben
if (strcmp(yourString, myString) == TRUE) // Wrong!!!
Das sieht legitim aus und der Compiler wird es gerne akzeptieren, aber es macht wahrscheinlich nicht das, was Sie wollen. Das liegt daran, dass der Rückgabewert von strcmp()
ist
0 if yourString == myString
<0 if yourString < myString
> 0 ifyourString > myString
Die obige Zeile kehrt also TRUE
nur zurück, wenn yourString > myString
.
Der richtige Weg, dies zu tun, ist entweder
// Valid, but still treats int as bool.
if (strcmp(yourString, myString))
oder
// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)
Ähnlich:
if (someBoolValue == FALSE) // Redundant.
if (!someBoolValue) // Better.
return (x > 0) ? TRUE : FALSE; // You're fired.
return (x > 0); // Simpler, clearer, correct.
if (ptr == NULL) // Perfect: compares pointers.
if (!ptr) // Sleazy, but short and valid.
if (ptr == FALSE) // Whatisthisidonteven.
Einige dieser "schlechten Beispiele" finden Sie häufig im Produktionscode, und viele erfahrene Programmierer schwören darauf: Sie funktionieren, einige sind kürzer als ihre (pedantisch?) Richtigen Alternativen, und die Redewendungen sind fast allgemein anerkannt. Aber bedenken Sie: Die "richtigen" Versionen sind nicht weniger effizient, sie sind garantiert portabel, sie bestehen selbst die strengsten Linters und selbst neue Programmierer werden sie verstehen.
Ist das das nicht wert?
(1==1)
ist nicht tragbarer als 1
. Die eigenen Regeln des Compilers sind die der C-Sprache, die klar und eindeutig in Bezug auf die Semantik von Gleichheits- und Vergleichsoperatoren ist. Ich habe noch nie einen Compiler gesehen, der dieses Zeug falsch verstanden hat.
strcmp
ist bekannt, dass der von zurückgegebene Wert kleiner als, gleich oder größer als 0 ist. Es ist nicht garantiert, dass er -1, 0 oder 1 ist, und es gibt Plattformen in freier Wildbahn, die diese Werte nicht zurückgeben, um die Implementierungsgeschwindigkeit zu erhöhen. Also wenn strcmp(a, b) == TRUE
dann a > b
aber umgekehrte Implikation möglicherweise nicht gilt.
(1==1)
und 1
sind beide konstanten Ausdrücke des Typs int
mit dem Wert 1. Sie semantisch identisch sind. Ich nehme an, Sie können Code schreiben, der sich an Leser richtet, die das nicht wissen, aber wo endet er?
Der (1 == 1)
Trick ist nützlich zum DefinierenTRUE
auf eine Weise , die für C transparent ist und dennoch eine bessere Eingabe in C ++ ermöglicht. Der gleiche Code kann als C oder C ++ interpretiert werden, wenn Sie in einem Dialekt namens "Clean C" schreiben (der entweder als C oder C ++ kompiliert wird) oder wenn Sie API-Header-Dateien schreiben, die von C- oder C ++ - Programmierern verwendet werden können.
Hat in C-Übersetzungseinheiten 1 == 1
genau die gleiche Bedeutung wie 1
; und 1 == 0
hat die gleiche Bedeutung wie 0
. Hat jedoch in den C ++ - Übersetzungseinheiten den 1 == 1
Typ bool
. Das so TRUE
definierte Makro lässt sich also besser in C ++ integrieren.
Ein Beispiel für eine bessere Integration ist beispielsweise, wenn die Funktion foo
überlastet istint
und für hat bool
, foo(TRUE)
die bool
Überlastung ausgewählt wird. Wenn TRUE
es nur als definiert ist 1
, funktioniert es in C ++ nicht gut. foo(TRUE)
will das wollenint
Überlastung.
Natürlich eingeführt C99 bool
, true
und false
diese können in Header - Dateien verwendet werden , dass die Arbeit mit C99 und mit C.
Jedoch:
TRUE
und FALSE
als (0==0)
und (1==0)
vor C99.Wenn Sie in einem gemischten C- und C ++ - Projekt arbeiten und C99 nicht möchten, definieren Sie die Kleinbuchstaben true
.false
und bool
stattdessen.
#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif
Davon abgesehen, die 0==0
abgesehen wurde (wird?) Trick von einigen Programmierern sogar in Code verwendet, der niemals dazu gedacht war, in irgendeiner Weise mit C ++ zusammenzuarbeiten. Das kauft nichts und deutet darauf hin, dass der Programmierer ein Missverständnis darüber hat, wie Boolesche Werte in C funktionieren.
Falls die C ++ - Erklärung nicht klar war, finden Sie hier ein Testprogramm:
#include <cstdio>
void foo(bool x)
{
std::puts("bool");
}
void foo(int x)
{
std::puts("int");
}
int main()
{
foo(1 == 1);
foo(1);
return 0;
}
Die Ausgabe:
bool
int
Zur Frage aus den Kommentaren, wie überladene C ++ - Funktionen für die gemischte C- und C ++ - Programmierung relevant sind. Diese veranschaulichen nur einen Typunterschied. Ein gültiger Grund dafür, dass eine true
Konstante bool
beim Kompilieren als C ++ verwendet werden soll, ist die saubere Diagnose. Bei den höchsten Warnstufen warnt uns ein C ++ - Compiler möglicherweise vor einer Konvertierung, wenn wir eine Ganzzahl als bool
Parameter übergeben. Ein Grund für das Schreiben in Clean C ist nicht nur, dass unser Code portabler ist (da er von C ++ - Compilern verstanden wird, nicht nur von C-Compilern), sondern wir können auch von den diagnostischen Meinungen von C ++ - Compilern profitieren.
TRUE
unter C ++ unterscheiden.
#ifdef __cplusplus
Ihre Absicht viel klarer ausdrücken.
bool
und int
in der Praxis keine große Rolle spielen, da sie implizit ineinander konvertierbar sind (und in C tatsächlich "gleich" die Anführungszeichen beachten obwohl,) und es gibt nicht viele Situationen , in denen Sie wirklich brauchen disambuigate zwischen den beiden. "nicht viel" war wahrscheinlich zu schwer, "viel weniger im Vergleich zu Code mit Vorlagen und Überladung" wäre vielleicht besser gewesen.
#define TRUE (1==1)
#define FALSE (!TRUE)
ist äquivalent zu
#define TRUE 1
#define FALSE 0
in C.
Das Ergebnis der Vergleichsoperatoren ist 0
oder 1
. 1==1
wird garantiert bewertet 1
und !(1==1)
wird garantiert bewertet0
.
Es gibt absolut keinen Grund, das erste Formular zu verwenden. Beachten Sie, dass das erste Formular jedoch nicht weniger effizient ist, da bei fast allen Compilern ein konstanter Ausdruck eher zur Kompilierungszeit als zur Laufzeit ausgewertet wird. Dies ist nach dieser Regel zulässig:
(C99, 6.6p2) "Ein konstanter Ausdruck kann während der Übersetzung und nicht zur Laufzeit ausgewertet werden und kann dementsprechend an jeder Stelle verwendet werden, an der sich eine Konstante befindet."
PC-Lint gibt sogar eine Nachricht aus (506, Boolescher Wert mit konstantem Wert), wenn Sie kein Literal für TRUE
und FALSE
Makros verwenden:
Für C,
TRUE
sollte definiert werden, zu sein1
. Andere Sprachen verwenden jedoch andere Mengen als 1, sodass einige Programmierer das Gefühl haben, auf!0
Nummer sicher zu gehen.
Auch in C99 verwenden die stdbool.h
Definitionen für Boolesche Makros true
und false
direkt Literale:
#define true 1
#define false 0
1==1
wird garantiert bis1
if(foo == true)
, der von einer schlechten Praxis zu einem fehlerhaften Buggy wird.
(x == TRUE)
kann einen anderen Wahrheitswert haben als x
.
Neben C ++ (bereits erwähnt) sind statische Analysewerkzeuge ein weiterer Vorteil. Der Compiler beseitigt Ineffizienzen, aber ein statischer Analysator kann seine eigenen abstrakten Typen verwenden, um zwischen Vergleichsergebnissen und anderen ganzzahligen Typen zu unterscheiden. Daher weiß er implizit, dass TRUE das Ergebnis eines Vergleichs sein muss und nicht als kompatibel angenommen werden sollte mit einer ganzen Zahl.
Offensichtlich sagt C, dass sie kompatibel sind, aber Sie können sich dafür entscheiden, die absichtliche Verwendung dieser Funktion zu verbieten, um Fehler hervorzuheben - zum Beispiel, wenn jemand verwirrt hat &
und &&
oder sie ihre Operator-Priorität verpfuscht haben.
if (boolean_var == TRUE)
durch Erweiterung abfangen, auf if (boolean_var == (1 == 1))
den dank der erweiterten Typinformationen des (1 == 1)
Knotens in das Muster fällt if (<*> == <boolean_expr>)
.
Der praktische Unterschied ist keiner. 0
wird ausgewertet false
und 1
ausgewertet true
. Die Tatsache, dass Sie einen booleschen Ausdruck ( 1 == 1
) oder 1
zum Definieren verwenden true
, macht keinen Unterschied. Sie werden beide ausgewertetint
.
Beachten Sie, dass die C-Standardbibliothek einen bestimmten Header zum Definieren von Booleschen Werten enthält : stdbool.h
.
true
wird ausgewertet 1
und false
ausgewertet 0
. C weiß nichts über native boolesche Typen, sie sind nur Ints.
int
mit dem Wert 0
oder 1
. C hat einen tatsächlichen booleschen Typ ( _Bool
mit einem in bool
definierten Makro <stdbool.h>
, das jedoch nur in C99 hinzugefügt wurde, wodurch die Semantik der Operatoren für die Verwendung des neuen Typs nicht geändert wurde.
_Bool
und <stdbool.h>
hat #define bool _Bool
.
1 == 1
Bewertung als int
. Bearbeitet.
Wir kennen den genauen Wert, dem TRUE entspricht, nicht und die Compiler können ihre eigenen Definitionen haben. Was Sie also privilegieren, ist die Verwendung des internen Compilers für die Definition. Dies ist nicht immer erforderlich, wenn Sie gute Programmiergewohnheiten haben, kann jedoch Probleme für einen schlechten Codierungsstil vermeiden, zum Beispiel:
if ((a> b) == TRUE)
Dies kann eine Katastrophe sein, wenn Sie TRUE manuell als 1 definieren, während der interne Wert von TRUE ein anderer ist.
>
liefert der Operator immer 1 für wahr, 0 für falsch. Es gibt keine Möglichkeit, dass ein C-Compiler dies falsch macht. Gleichheitsvergleiche TRUE
und FALSE
schlechter Stil; das obige ist klarer geschrieben als if (a > b)
. Aber die Idee, dass verschiedene C-Compiler Wahrheit und Falsch unterschiedlich behandeln können, ist einfach falsch.
In der Programmiersprache C wird normalerweise 1 als wahr und 0 als falsch definiert. Deshalb sehen Sie ziemlich oft Folgendes:
#define TRUE 1
#define FALSE 0
Jede Zahl ungleich 0 würde jedoch auch in einer bedingten Anweisung als wahr bewertet. Verwenden Sie daher Folgendes:
#define TRUE (1==1)
#define FALSE (!TRUE)
Sie können nur explizit zeigen, dass Sie versuchen, auf Nummer sicher zu gehen, indem Sie false gleich dem machen, was nicht wahr ist.
#define TRUE (’/’/’/’)
;#define FALSE (’-’-’-’)
(entnommen aus coding-guidelines.com/cbook/cbook1_1.pdf Seite 871)