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?
SLaks
Dieser Ansatz verwendet das Ist boolean
eingeben (und auflösen true
und false
), wenn der Compiler dies unterstützt. (insbesondere C++)
Es wäre jedoch besser zu prüfen, ob C++ verwendet wird (über die __cplusplus
Makro) und tatsächlich verwenden true
und false
.
In einem C-Compiler ist dies äquivalent zu 0
und 1
.
(Beachten Sie, dass das Entfernen der Klammern dies aufgrund der Reihenfolge der Operationen unterbricht)
Das ist falsch, Bools werden hier nicht verwendet. Das Ergebnis von 1==1
ist ein int
. (siehe stackoverflow.com/questions/7687403/… .)
– Matte
9. Juni 2013 um 13:34 Uhr
@Mat: Sogar in C++, mit der boolean
Typ?
– SLaks
9. Juni 2013 um 13:35 Uhr
Die Frage ist mit C gekennzeichnet, aber in C++ kehren die Vergleichsoperatoren tatsächlich zurück true
oder false
.
– Matte
9. Juni 2013 um 13:37 Uhr
@Mat: Ich vermute, dass solcher Code in C-Headern geschrieben ist, um gut mit C++ zu spielen
– SLaks
9. Juni 2013 um 13:38 Uhr
@SLaks Wenn es gut mit C++ spielen wollte, würde es das tun #define TRUE true
und #define FALSE false
wann immer __cplusplus
ist definiert.
– Nikos C.
9. Juni 2013 um 13:46 Uhr
Adam Liss
Die Antwort ist Portabilität. Die numerischen Werte von TRUE
und FALSE
sind nicht wichtig. Was ist Wichtig ist, dass eine Aussage wie if (1 < 2)
wertet zu if (TRUE)
und eine Aussage wie if (1 > 2)
wertet zu if (FALSE)
.
Zugegeben, in C, (1 < 2)
wertet zu 1
und (1 > 2)
wertet zu 0
, also gibt es, wie andere gesagt haben, keinen praktischen Unterschied, was den Compiler betrifft. Aber indem man den Compiler definieren lässt TRUE
und FALSE
nach ihren eigenen Regeln machen Sie ihre Bedeutung für Programmierer deutlich und garantieren die Konsistenz innerhalb Ihres Programms und jeder anderen Bibliothek (vorausgesetzt, die andere Bibliothek folgt den C-Standards … Sie wären erstaunt).
Einige Geschichten
Einige BASICs definiert FALSE
wie 0
und TRUE
wie -1
. Wie viele moderne Sprachen, sie interpretiert jeder Wert ungleich Null als TRUE
aber sie ausgewertet boolesche Ausdrücke, die als wahr waren -1
. Ihr NOT
Die Operation wurde durch Addieren von 1 und Umdrehen des Vorzeichens implementiert, weil es so effizient war. So wurde ‘NOT x’ -(x+1)
. Ein Nebeneffekt davon ist, dass ein Wert wie 5
wertet zu TRUE
aber NOT 5
wertet zu -6
was auch ist TRUE
! Es macht keinen Spaß, solche Fehler zu finden.
Empfohlene Vorgehensweise
Angesichts der de facto Regeln, als die Null interpretiert wird FALSE
und irgendein ein Wert ungleich Null wird interpretiert als TRUE
Du solltest Vergleichen Sie niemals boolesch aussehende Ausdrücke mit TRUE
oder FALSE
. Beispiele:
if (thisValue == FALSE) // Don't do this!
if (thatValue == TRUE) // Or this!
if (otherValue != TRUE) // Whatever you do, don't do this!
Wieso den? Weil viele Programmierer die Abkürzung des Behandelns verwenden int
ist wie bool
s. Sie sind nicht gleich, aber Compiler erlauben es im Allgemeinen. So ist es zum Beispiel vollkommen legal zu schreiben
if (strcmp(yourString, myString) == TRUE) // Wrong!!!
Dass sieht aus legitim, und der Compiler wird es gerne akzeptieren, aber es tut wahrscheinlich nicht das, was Sie wollen. Das liegt daran, dass der Rückgabewert von strcmp()
ist
0 wenn yourString == myString
<0 wenn yourString < myString
>0 wenn yourString > myString
Die obige Zeile kehrt also zurück TRUE
nur 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 oft im Produktionscode, und viele erfahrene Programmierer schwören auf sie: Sie funktionieren, einige sind kürzer als ihre (umständlich?) korrekten 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.
Lohnt sich das nicht?
(1==1)
ist nicht tragbarer als 1
. Die eigenen Regeln des Compilers sind die der C-Sprache, die bezüglich der Semantik von Gleichheits- und Vergleichsoperatoren klar und eindeutig ist. Ich habe noch nie gesehen, dass ein Compiler dieses Zeug falsch gemacht hat.
– Keith Thompson
9. Juni 2013 um 21:25 Uhr
Eigentlich der Wert, der von zurückgegeben wird strcmp
ist bekanntermaßen kleiner, gleich oder größer als 0. Es ist nicht garantiert, dass es -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 die umgekehrte Implikation gilt möglicherweise nicht.
– Maciej Piechotka
10. Juni 2013 um 1:23 Uhr
@KeithThompson – Vielleicht war “Portabilität” der falsche Begriff. Aber Tatsache bleibt, dass (1==1) ein boolescher Wert ist; 1 nicht.
– Adam Liss
10. Juni 2013 um 1:31 Uhr
@AdamLiss: In C, (1==1)
und 1
sind beides konstante Ausdrücke des Typs int
mit dem Wert 1. Sie sind semantisch identisch. Ich nehme an, Sie können Code schreiben, der für Leser geeignet ist, die das nicht wissen, aber wo endet das?
– Keith Thompson
10. Juni 2013 um 1:40 Uhr
‘nicht’ 5 ist tatsächlich -6 auf Bitebene.
– woliveirajr
10. Juni 2013 um 12:47 Uhr
Kaz
Das (1 == 1)
Trick ist nützlich für die Definition TRUE
auf eine Weise, die für C transparent ist, aber eine bessere Eingabe in C++ ermöglicht. Derselbe 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.
In C-Übersetzungseinheiten, 1 == 1
hat genau die gleiche Bedeutung wie 1
; und 1 == 0
hat die gleiche Bedeutung wie 0
. In den C++-Übersetzungseinheiten 1 == 1
Typ hat bool
. Also die TRUE
Ein so definiertes Makro lässt sich besser in C++ integrieren.
Ein Beispiel dafür, wie es sich besser integrieren lässt, ist zum Beispiel if function foo
hat Überladungen für int
und für bool
dann foo(TRUE)
wird die wählen bool
Überlast. Wenn TRUE
ist nur definiert als 1
dann funktioniert es in C++ nicht gut. foo(TRUE)
will die int
Überlast.
Natürlich C99 eingeführt bool
, true
und false
und diese können in Header-Dateien verwendet werden, die mit C99 und mit C funktionieren.
Jedoch:
TRUE
und FALSE
wie (0==0)
und (1==0)
älter als C99.Wenn Sie in einem gemischten C- und C++-Projekt arbeiten und C99 nicht möchten, definieren Sie die Kleinschreibung true
, false
und bool
stattdessen.
#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif
Davon abgesehen, die 0==0
trick wurde (wird?) von einigen Programmierern sogar in Code verwendet, der nie dazu gedacht war, in irgendeiner Weise mit C++ zu interagieren. 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, hier ist 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
Zu der Frage aus den Kommentaren, wie überladene C++-Funktionen für die gemischte C- und C++-Programmierung relevant sind. Diese veranschaulichen nur einen Typunterschied. Ein triftiger Grund für den Wunsch nach a true
konstant zu sein bool
wenn es als C++ kompiliert wird, dient es der sauberen Diagnose. Auf den höchsten Warnstufen könnte uns ein C++-Compiler vor einer Konvertierung warnen, wenn wir eine ganze Zahl als a übergeben bool
Parameter. Ein Grund für das Schreiben in Clean C ist nicht nur, dass unser Code besser portierbar ist (da er von C++-Compilern verstanden wird, nicht nur von C-Compilern), sondern wir können von den diagnostischen Meinungen von C++-Compilern profitieren.
Ausgezeichnete und unterschätzte Antwort. Es ist überhaupt nicht offensichtlich, dass die beiden Definitionen von TRUE
wird sich unter C++ unterscheiden.
– Benutzer4815162342
9. Juni 2013 um 20:35 Uhr
Wie sind überladene Funktionen für Code relevant, der sowohl als C als auch als C++ kompiliert wird?
– Keith Thompson
9. Juni 2013 um 21:19 Uhr
@KeithThompson Es geht nicht nur um das Überladen, sondern um das richtige Tippen im Allgemeinen. Überladen ist nur das praktischste Beispiel, wenn es ins Spiel kommt. Natürlich C++-Code ohne Überladungen, Templates und all das “komplizierte” Zeug entfernt “C-Kompatibilität” kümmert sich nicht wirklich um Typen, aber das bedeutet nicht, dass man die stürzen sollte konzeptionell Typbeschränkungen in einer bestimmten Sprache.
– Christian Rau
10. Juni 2013 um 10:47 Uhr
@ChristianRau: Was meinst du mit “kümmert sich nicht wirklich um Typen”? Typen sind von zentraler Bedeutung für die C-Sprache; Jeder Ausdruck, Wert und jedes Objekt in einem C-Programm hat einen wohldefinierten Typ. Wenn Sie in C etwas anders definieren wollen als in C++ (in der Selten Fällen, in denen Sie tatsächlich Code schreiben müssen, der sowohl als C als auch als C++ kompiliert wird), können Sie verwenden #ifdef __cplusplus
um Ihre Absicht viel klarer auszudrücken.
– Keith Thompson
10. Juni 2013 um 14:55 Uhr
@KeithThompson Ja, ich weiß, wie wichtig Typen sind. Es ist nur so, dass ohne all das typbewusste Zeug wie Überladen und Vorlagen, Dinge wie die Unterscheidung zwischen bool
und int
spielen in der Praxis keine große Rolle, da sie implizit ineinander konvertierbar sind (und in C eigentlich “das Gleiche”beachten Sie jedoch die Anführungszeichen) und es gibt nicht viele Situationen, in denen Sie dies wirklich tun müssen ausräumen zwischen den beiden. “wenig” War wohl zu schwer, “viel weniger im Vergleich zu Code, der Vorlagen verwendet und überlädt” wäre vielleicht besser gewesen.
– Christian Rau
10. Juni 2013 um 15:35 Uhr
ouah
#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 ausgewertet 1
und !(1==1)
wird garantiert ausgewertet 0
.
Es gibt absolut keinen Grund, die erste Form zu verwenden. Beachten Sie, dass die erste Form jedoch nicht weniger effizient ist, da bei fast allen Compilern ein konstanter Ausdruck zur Kompilierzeit und nicht zur Laufzeit ausgewertet wird. Dies ist nach dieser Regel erlaubt:
(C99, 6.6p2) “Ein konstanter Ausdruck kann eher während der Übersetzung als zur Laufzeit ausgewertet werden und kann dementsprechend an jeder Stelle verwendet werden, an der sich eine Konstante befindet.”
PC-Lint gibt sogar eine Meldung aus (506, konstanter Wert boolean), wenn Sie kein Literal für verwenden TRUE
und FALSE
Makros:
Für C,
TRUE
sollte definiert werden1
. Andere Sprachen verwenden jedoch andere Mengen als 1, so dass einige Programmierer das glauben!0
geht auf Nummer sicher.
Auch in C99, die stdbool.h
Definitionen für boolesche Makros true
und false
direkt Literale verwenden:
#define true 1
#define false 0
Neben C++ (bereits erwähnt) gibt es einen weiteren Vorteil für statische Analysewerkzeuge. Der Compiler beseitigt alle Ineffizienzen, aber ein statischer Analysator kann seine eigenen abstrakten Typen verwenden, um zwischen Vergleichsergebnissen und anderen ganzzahligen Typen zu unterscheiden, sodass er implizit weiß, dass TRUE das Ergebnis eines Vergleichs sein muss und nicht als kompatibel angenommen werden sollte mit einer Ganzzahl.
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 sein könnte &
und &&
oder sie haben ihre Operatorpriorität verpfuscht.
Das ist ein guter Punkt, und vielleicht können einige dieser Tools sogar dummen Code abfangen if (boolean_var == TRUE)
durch Erweiterung zu if (boolean_var == (1 == 1))
was dank der erweiterten Typinfo der (1 == 1)
Knoten fällt in das Muster if (<*> == <boolean_expr>)
.
– Kas
9. Juni 2013 um 18:06 Uhr
Der praktische Unterschied ist keiner. 0
ausgewertet wird false
und 1
ausgewertet wird true
. Die Tatsache, dass Sie a verwenden Boolescher Ausdruck (1 == 1
) oder 1
definieren true
, spielt keine Rolle. Sie werden beide bewertet int
.
Beachten Sie, dass die C-Standardbibliothek einen speziellen Header zum Definieren von booleschen Werten bereitstellt: stdbool.h
.
Das ist ein guter Punkt, und vielleicht können einige dieser Tools sogar dummen Code abfangen if (boolean_var == TRUE)
durch Erweiterung zu if (boolean_var == (1 == 1))
was dank der erweiterten Typinfo der (1 == 1)
Knoten fällt in das Muster if (<*> == <boolean_expr>)
.
– Kas
9. Juni 2013 um 18:06 Uhr
capiggue
Wir kennen den genauen Wert, dem TRUE entspricht, nicht und die Compiler können ihre eigenen Definitionen haben. Was Sie also bevorzugen, ist, die interne des Compilers für die Definition zu verwenden. Dies ist nicht immer notwendig, wenn Sie gute Programmiergewohnheiten haben, kann aber Probleme für einen schlechten Programmierstil vermeiden, zum Beispiel:
wenn ( (a > b) == WAHR)
Dies könnte eine Katastrophe sein, wenn Sie TRUE manuell als 1 definieren, während der interne Wert von TRUE ein anderer ist.
In C, die >
Operator liefert immer 1 für wahr, 0 für falsch. Es besteht keine Möglichkeit, dass ein C-Compiler dies falsch macht. Gleichstellungsvergleiche zu TRUE
und FALSE
sind schlechter Stil; das obige ist deutlicher geschrieben als if (a > b)
. Aber die Idee, dass verschiedene C-Compiler wahr und falsch unterschiedlich behandeln können, ist einfach falsch.
– Keith Thompson
14. Oktober 2013 um 22:52 Uhr
Und mehr:
#define TRUE (’/’/’/’)
;#define FALSE (’-’-’-’)
(genommen von Coding-Guidelines.com/cbook/cbook1_1.pdf Seite 871)– osgx
9. Juni 2013 um 14:03 Uhr
Nein, es ist Paranoia der Ahnungslosen^Wunderinformiert, wirklich. In C tun 1 und 0 unter allen Umständen dasselbe.
– Jens
9. Juni 2013 um 16:05 Uhr
@osgx Was bedeutet das?
– Mrgloom
9. Juli 2019 um 18:15 Uhr