Ziel-C: BOOL gegen Bool

192

Ich habe den "neuen Typ" BOOL( YES, NO) gesehen.

Ich habe gelesen, dass dieser Typ fast wie ein Saibling ist.

Zum Testen habe ich gemacht:

NSLog(@"Size of BOOL %d", sizeof(BOOL));
NSLog(@"Size of bool %d", sizeof(bool));

Gut zu sehen, dass beide Protokolle "1" anzeigen (manchmal ist in C ++ bool ein int und seine Größe ist 4)

Also habe ich mich nur gefragt, ob es Probleme mit dem Bool-Typ gibt oder so?

Kann ich einfach bool verwenden (das scheint zu funktionieren), ohne an Geschwindigkeit zu verlieren?

Francescu
quelle

Antworten:

198

Aus der Definition in objc.h:

#if (TARGET_OS_IPHONE && __LP64__)  ||  TARGET_OS_WATCH
typedef bool BOOL;
#else
typedef signed char BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#endif

#define YES ((BOOL)1)
#define NO  ((BOOL)0)

Also, ja, Sie können davon ausgehen, dass BOOL ein Zeichen ist. Sie können den boolTyp (C99) verwenden, aber alle Objective-C-Frameworks von Apple und die meisten Objective-C / Cocoa-Codes verwenden BOOL, sodass Sie sich Kopfschmerzen ersparen, wenn sich der Typedef jemals ändert, indem Sie nur BOOL verwenden.

Barry Wark
quelle
17
"Alle Frameworks von Apple" - nicht wahr. Schauen Sie sich CGGeometry.h an, insbesondere: CG_INLINE bool __CGPointEqualToPoint (CGPoint point1, CGPoint point2) {return point1.x == point2.x && point1.y == point2.y; }
Elliot
58
@Elliot Du bist richtig. Viele der C-Frameworks (CoreFoundation, CoreGraphics usw.) verwenden C99 bool. Alle Objective-C-Frameworks verwenden BOOL.
Barry Wark
@ Cœur Sie haben die Definition des BOOL-Codebeispiels bearbeitet, aber der folgende Text bleibt gleich. Es ist ein bisschen verwirrend und falsch. Siehe meine Antwort.
neugierig
Ich habe verschiedene Verhaltensweisen kennengelernt, siehe unten. NSInteger progressTime = 2;//any value NSInteger totalTime = 1;//any value BOOL success = (progressTime>=totalTime)// es gibt immer gibt NO Aber sobald ich diesen (progressTime>=totalTime)Wert in boolTyp erhalten successhabe, gibt es das richtige Ergebnis zurück. Ich verstehe dieses Verhalten nicht. Ich benutze Xcode 7.xund die iOSVersion war 8.x. @ BarryWark
Kamar Shad
34

Wie oben erwähnt, ist BOOL ein signiertes Zeichen. Bool - Typ aus C99 Standard (int).

BOOL - JA / NEIN. bool - wahr / falsch.

Siehe Beispiele:

bool b1 = 2;
if (b1) printf("REAL b1 \n");
if (b1 != true) printf("NOT REAL b1 \n");

BOOL b2 = 2;
if (b2) printf("REAL b2 \n");
if (b2 != YES) printf("NOT REAL b2 \n");

Und das Ergebnis ist

REAL b1
REAL b2
NICHT REAL b2

Beachten Sie, dass bool! = BOOL. Ergebnis unten ist nur EINMAL WIEDER - REAL b2

b2 = b1;
if (b2) printf("ONCE AGAIN - REAL b2 \n");
if (b2 != true) printf("ONCE AGAIN - NOT REAL b2 \n");

Wenn Sie bool in BOOL konvertieren möchten, sollten Sie den nächsten Code verwenden

BOOL b22 = b1 ? YES : NO; //and back - bool b11 = b2 ? true : false;

Also in unserem Fall:

BOOL b22 = b1 ? 2 : NO;
if (b22)    printf("ONCE AGAIN MORE - REAL b22 \n");
if (b22 != YES) printf("ONCE AGAIN MORE- NOT REAL b22 \n");

Und so ... was bekommen wir jetzt? :-)

Beryllium
quelle
3
Sie könnten anstelle des ternären Operators verwenden !!b1. Um zwischen ihnen zu konvertieren
Richard J. Ross III
1
'NOT REAL b2' ist auf meinem iPhone SE-Simulator nicht gedruckt.
Gabbler
12

Zum Zeitpunkt des Schreibens ist dies die neueste Version von objc.h:

/// Type to represent a boolean value.
#if (TARGET_OS_IPHONE && __LP64__)  ||  TARGET_OS_WATCH
#define OBJC_BOOL_IS_BOOL 1
typedef bool BOOL;
#else
#define OBJC_BOOL_IS_CHAR 1
typedef signed char BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#endif

Dies bedeutet, dass auf 64-Bit-iOS-Geräten und unter WatchOS BOOLgenau dasselbe ist wie boolauf allen anderen Geräten (OS X, 32-Bit-iOS) signed charund nicht einmal durch das Compiler-Flag überschrieben werden kann-funsigned-char

Dies bedeutet auch, dass dieser Beispielcode auf verschiedenen Plattformen unterschiedlich ausgeführt wird (selbst getestet):

int myValue = 256;
BOOL myBool = myValue;
if (myBool) {
    printf("i'm 64-bit iOS");
} else {
    printf("i'm 32-bit iOS");
}

BTW nie assign Dinge wie array.countzu BOOLvariabel , da etwa 0,4% der möglichen Werte negativ sein wird.

Piotr Tobolski
quelle
Der Compiler gibt einen Fehler aus, wenn Sie bool als Parameter eines Blocks verwenden, der zum Abrufen eines BOOL definiert ist (z. B. UIView-Animationsblöcke), wenn Sie für iOS 32 Bit kompilieren (iPhone 5C ...). Ich verwende C ++ bool überall in meinem Code und BOOL in den APIs, die mit BOOL
stephane k definiert sind.
8

Der Objective-C-Typ, den Sie verwenden sollten, ist BOOL. Es gibt nichts Schöneres als einen nativen booleschen Datentyp. Stellen Sie daher sicher, dass der Code auf allen Compilern kompiliert wird BOOL. (Es ist in den Apple-Frameworks definiert.

Georg Schölly
quelle
2
Dies ist nicht genau. BOOLwird durch die Objective-C-Sprache (in einem der objc/*.hHeader) definiert, nicht durch die Frameworks. Außerdem gibt es beim Kompilieren mit C99 (was meiner Meinung nach die Standardeinstellung ist) einen nativen Booleschen Typ _Bool(oder boolfalls stdbool.henthalten).
Dreamlax
5

Ja, BOOL ist ein typedef für ein signiertes Zeichen gemäß objc.h.

Ich weiß allerdings nichts über Bool. Das ist eine C ++ - Sache, oder? Wenn es als vorzeichenbehaftetes Zeichen definiert ist, wobei 1 JA / wahr und 0 NEIN / falsch ist, dann ist es meiner Meinung nach egal, welches Sie verwenden.

Da BOOL jedoch Teil von Objective-C ist, ist es aus Gründen der Übersichtlichkeit wahrscheinlich sinnvoller, ein BOOL zu verwenden (andere Objective-C-Entwickler sind möglicherweise verwirrt, wenn sie sehen, dass ein Bool verwendet wird).

Jeff
quelle
6
_Bool ist in C99 definiert, und im Standardheader stdbool.h ist das Makro-Bool definiert (das zu _Bool erweitert wird), und auch hier sind true / false definiert.
Brian Mitchell
4

Ein weiterer Unterschied zwischen bool und BOOL besteht darin, dass sie nicht genau in dieselbe Art von Objekten konvertiert werden, wenn Sie Schlüsselwerte beobachten oder Methoden wie - [NSObject valueForKey:] verwenden.

Wie jeder hier gesagt hat, ist BOOL char. Als solches wird es in eine NSNumber konvertiert, die ein Zeichen enthält. Dieses Objekt ist nicht von einer NS-Nummer zu unterscheiden, die aus einem regulären Zeichen wie 'A' oder '\ 0' erstellt wurde. Sie haben die Information, dass Sie ursprünglich einen BOOL hatten, völlig verloren.

Bool wird jedoch in einen CFBoolean konvertiert, der sich wie NSNumber verhält, jedoch den booleschen Ursprung des Objekts beibehält.

Ich denke nicht, dass dies ein Argument in einer Debatte zwischen BOOL und Bool ist, aber dies könnte Sie eines Tages beißen.

Im Allgemeinen sollten Sie sich für BOOL entscheiden, da dies der Typ ist, der überall in den Cocoa / iOS-APIs verwendet wird (entwickelt vor C99 und seinem nativen Bool-Typ).

Gwendal Roué
quelle
2

Die akzeptierte Antwort wurde bearbeitet und ihre Erklärung ist etwas falsch. Das Codebeispiel wurde aktualisiert, der folgende Text bleibt jedoch unverändert. Sie können vorerst nicht davon ausgehen, dass BOOL ein Zeichen ist, da es von der Architektur und der Plattform abhängt. Wenn Sie also Ihren Code auf einer 32-Bit-Plattform (z. B. iPhone 5) ausführen und @encode (BOOL) drucken, wird "c" angezeigt. Es entspricht einem Zeichentyp . Wenn Sie Ihren Code jedoch auf dem iPhone 5s (64 Bit) ausführen, wird "B" angezeigt. Es entspricht einem Bool-Typ .

neugierig
quelle
1

Ich verstoße hier gegen die Konvention. Ich mag keine Typedefs zu Basistypen. Ich denke, es ist eine nutzlose Indirektion, die Wert entfernt.

  1. Wenn ich den Basistyp in Ihrer Quelle sehe, werde ich ihn sofort verstehen. Wenn es ein Typedef ist, muss ich es nachschlagen, um zu sehen, womit ich es wirklich zu tun habe.
  2. Wenn Sie auf einen anderen Compiler portieren oder eine andere Bibliothek hinzufügen, kann dies zu Konflikten führen und Probleme verursachen, die schwer zu debuggen sind. Ich bin gerade damit fertig geworden. In einer Bibliothek wurde der Boolesche Wert in int eingegeben, und in mingw / gcc wurde er in ein Zeichen eingegeben.
Jay
quelle
4
Nun ... es kann erwartet werden, dass Sie die Standard-Typedefs Ihrer Sprache kennen (denken size_t), und sowohl bool(C99) als auch BOOL(ObjC) fallen in diese Kategorie. Und wenn Ihr Code aufgrund einer Änderung von typedef fehlgeschlagen ist, ist Ihr Code schuld, da Sie den typedef anscheinend nicht als undurchsichtig behandelt haben, sondern sich auf seine Implementierung auf einer Plattform verlassen haben. (Nichts, wofür man sich schämen muss, es passiert, aber es ist nicht der Typedef, der die Schuld trägt.)
DevSolar
1
Die "Standard" -Typedefs scheinen nicht sehr Standard zu sein (zum Beispiel hat MS eine Zeit lang keine Posix-Standards usw. unterstützt). Wenn Sie keine typedefs verwenden, wird das Problem behoben, dass sich typedefs auf verschiedenen Compilern ändern oder unterscheiden.
Jay
1
-1, Typedefs dienen im Allgemeinen zwei wichtigen Zwecken (unter anderem): Bereitstellung einer guten Semantik und Bereitstellung einer gewissen Fehlleitung. Idealerweise sollten Sie den Basistyp, auf den sich ein typedef bezieht, nicht kennen müssen. Leider ist dieses System nicht perfekt und manchmal müssen Sie es wissen. Mein Punkt ist: Sie sollten der Konvention folgen, denn selbst wenn Sie zugeben, dass sie nicht perfekt ist, ist sie besser als die Alternative.
João Portela
2
@ Jay: Sorry, ich hätte erklären sollen, warum diese "Fehlleitung" gut ist. Ich werde versuchen, ein Beispiel zu liefern: Wenn Sie den typedef'd-Booleschen Wert anstelle eines int oder eines char direkt verwenden, können Sie auf jeder Plattform einen anderen Typ (der immer noch funktioniert) verwenden, ohne Ihren Code zu beschädigen [Gründe für Dies ist unterschiedlich, aber wir können uns eine Plattform vorstellen, auf der ein Zeichen im Speicher falsch ausgerichtet und damit langsamer sein kann, sodass stattdessen ein int für einen Booleschen Wert verwendet werden kann.
João Portela
2
@ Jay: Mit "guter Semantik" meine ich, dass, wenn Sie BOOL varnamestattdessen Ihren Booleschen char varnameWert deklarieren, es offensichtlicher ist, dass die beiden gültigen Werte für diese Variable true/ YESoder false/ sind NO.
João Portela
1

Wie oben erwähnt, BOOLkann dies ein unsigned charTyp sein, der von Ihrer Architektur abhängt, während er boolvom Typ ist int. Ein einfaches Experiment zeigt den Unterschied, warum sich BOOL und Bool unterschiedlich verhalten können:

bool ansicBool = 64;
if(ansicBool != true) printf("This will not print\n");

printf("Any given vlaue other than 0 to ansicBool is evaluated to %i\n", ansicBool);

BOOL objcBOOL = 64;
if(objcBOOL != YES) printf("This might print depnding on your architecture\n");

printf("BOOL will keep whatever value you assign it: %i\n", objcBOOL);

if(!objcBOOL) printf("This will not print\n");

printf("! operator will zero objcBOOL %i\n", !objcBOOL);

if(!!objcBOOL) printf("!! will evaluate objcBOOL value to %i\n", !!objcBOOL);

Zu Ihrer Überraschung if(objcBOOL != YES)wird vom Compiler 1 bewertet, da YESes sich tatsächlich um den Zeichencode 1 handelt, und in den Augen des Compilers ist der Zeichencode 64 natürlich nicht gleich dem Zeichencode 1, daher wird die if-Anweisung als YES/true/1und die folgende Zeile ausgewertet Lauf. Da ein boolTyp ungleich Null immer den ganzzahligen Wert 1 ergibt, wirkt sich das oben genannte Problem nicht auf Ihren Code aus. Im Folgenden finden Sie einige gute Tipps, wenn Sie den Objective-C BOOLTyp im Vergleich zum ANSI C boolTyp verwenden möchten :

  • Weisen Sie immer den Wert YESoder NOund sonst nichts zu.
  • Konvertieren Sie BOOLTypen mit dem !!Operator double not , um unerwartete Ergebnisse zu vermeiden.
  • Bei der Überprüfung der YESVerwendung ist if(!myBool) instead of if(myBool != YES)es viel sauberer, den !Operator not zu verwenden , und es wird das erwartete Ergebnis erzielt.
ilgaar
quelle
1

Beachten Sie auch die Unterschiede beim Casting, insbesondere bei der Arbeit mit Bitmasken, aufgrund des Castings auf signiertes Zeichen:

bool a = 0x0100;
a == true;  // expression true

BOOL b = 0x0100;
b == false; // expression true on !((TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH), e.g. MacOS
b == true;  // expression true on (TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH

Wenn BOOL ein vorzeichenbehaftetes Zeichen anstelle eines Bools ist, wird bei der Umwandlung von 0x0100 in BOOL einfach das gesetzte Bit gelöscht, und der resultierende Wert ist 0.

michaf
quelle