Objectif-C: BOOL vs bool

192

J'ai vu le "nouveau type" BOOL( YES, NO).

J'ai lu que ce type est presque comme un caractère.

Pour les tests, j'ai fait:

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

C'est bien de voir que les deux journaux affichent "1" (parfois en C ++, bool est un entier et sa taille est 4)

Je me demandais donc s'il y avait des problèmes avec le type booléen ou quelque chose du genre?

Puis-je simplement utiliser bool (qui semble fonctionner) sans perdre de vitesse?

Francescu
la source

Réponses:

199

D'après la définition dans 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)

Donc, oui, vous pouvez supposer que BOOL est un caractère. Vous pouvez utiliser le type (C99) bool, mais tous les frameworks Objective-C d'Apple et la plupart des codes Objective-C / Cocoa utilisent BOOL, vous vous éviterez donc des maux de tête si le typedef change en utilisant simplement BOOL.

Barry Wark
la source
17
"tous les cadres d'Apple" - pas vrai. Jetez un œil à CGGeometry.h, en particulier: CG_INLINE bool __CGPointEqualToPoint (CGPoint point1, CGPoint point2) {return point1.x == point2.x && point1.y == point2.y; }
Elliot
58
@Elliot Vous avez raison. De nombreux frameworks C (CoreFoundation, CoreGraphics, etc.) utilisent C99 bool. Tous les frameworks Objective-C utilisent BOOL.
Barry Wark
@ Cœur vous avez édité la définition de l'exemple de code BOOL, mais le texte ci-dessous reste le même. C'est un peu déroutant et incorrect. Voyez ma réponse.
curieux
Vous devez connaître différents comportements, jetez un œil ci-dessous. NSInteger progressTime = 2;//any value NSInteger totalTime = 1;//any value BOOL success = (progressTime>=totalTime)// il donne toujours NO mais une fois que j'ai reçu cette (progressTime>=totalTime)valeur dans le booltype, successil renvoie le résultat correct. Je ne comprends pas ce comportement. J'utilise Xcode 7.xet la iOSversion était 8.x. @BarryWark
Kamar Shad
34

Comme mentionné ci-dessus, BOOL est un caractère signé. bool - type de la norme C99 (int).

BOOL - OUI / NON. booléen - vrai / faux.

Voir des exemples:

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");

Et le résultat est

RÉEL b1
RÉEL b2
PAS RÉEL b2

Notez que bool! = BOOL. Le résultat ci-dessous n'est encore qu'une fois - REAL b2

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

Si vous voulez convertir bool en BOOL, vous devez utiliser le code suivant

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

Donc, dans notre cas:

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");

Et donc ... ce que nous obtenons maintenant? :-)

béryllium
la source
3
Vous pouvez, au lieu d'utiliser l'opérateur ternaire, utiliser !!b1. Pour convertir entre eux
Richard J.Ross III
1
«NOT REAL b2» n'est pas imprimé sur mon simulateur iPhone SE.
gabbler
12

Au moment de la rédaction de cet article, il s'agit de la version la plus récente de 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

Cela signifie que sur les appareils iOS 64 bits et WatchOS, BOOLc'est exactement la même chose boolque sur tous les autres appareils (OS X, iOS 32 bits), il est signed charet ne peut même pas être remplacé par l'indicateur du compilateur-funsigned-char

Cela signifie également que cet exemple de code fonctionnera différemment sur différentes plates-formes (je l'ai testé moi-même):

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

BTW choses ne Assigner aiment array.countà BOOLvariables car environ 0,4% des valeurs possibles sera négatif.

Piotr Tobolski
la source
le compilateur lèvera une erreur si vous utilisez bool comme paramètre d'un bloc qui est défini pour obtenir un BOOL (blocs d'animation UIView, par exemple), lorsque vous compilez pour iOS 32 bits (iPhone 5C ...). J'utilise C ++ bool partout dans mon code et BOOL dans les API qui sont définies avec BOOL
stephane k.
8

Le type Objective-C que vous devez utiliser est BOOL. Il n'y a rien de tel qu'un type de données booléen natif, donc pour être sûr que le code compile sur tous les compilateurs utilisent BOOL. (Il est défini dans Apple-Frameworks.

Georg Schölly
la source
2
Ce n'est pas strictement exact. BOOLest défini par le langage Objective-C (c'est dans l'un des en- objc/*.htêtes), pas par les frameworks. De plus, lors de la compilation avec C99 (ce que je pense être la valeur par défaut), il existe un type booléen natif _Bool(ou bools'il stdbool.hest inclus).
dreamlax
5

Oui, BOOL est un typedef pour un caractère signé selon objc.h.

Je ne sais pas pour bool, cependant. C'est un truc C ++, non? S'il est défini comme un caractère signé où 1 est OUI / vrai et 0 est NON / faux, alors j'imagine que celui que vous utilisez n'a pas d'importance.

Puisque BOOL fait partie d'Objective-C, cependant, il est probablement plus logique d'utiliser un BOOL pour plus de clarté (d'autres développeurs d'Objective-C pourraient être perplexes s'ils voient un bool en cours d'utilisation).

Jeff
la source
6
_Bool est défini dans C99, et dans l'en-tête standard stdbool.h, la macro bool est définie (qui se développe en _Bool) et true / false sont également définis ici.
Brian Mitchell
4

Une autre différence entre bool et BOOL est qu'ils ne se convertissent pas exactement dans le même type d'objets, lorsque vous effectuez une observation clé-valeur ou lorsque vous utilisez des méthodes telles que - [NSObject valueForKey:].

Comme tout le monde l'a dit ici, BOOL est char. En tant que tel, il est converti en NSNumber contenant un char. Cet objet est indiscernable d'un NSNumber créé à partir d'un caractère normal comme «A» ou «\ 0». Vous avez totalement perdu l'information que vous aviez à l'origine un BOOL.

Cependant, bool est converti en CFBoolean, qui se comporte de la même manière que NSNumber, mais qui conserve l'origine booléenne de l'objet.

Je ne pense pas que ce soit un argument dans un débat BOOL vs bool, mais cela peut vous mordre un jour.

De manière générale, vous devriez aller avec BOOL, car c'est le type utilisé partout dans les API Cocoa / iOS (conçu avant C99 et son type booléen natif).

Gwendal Roué
la source
2

La réponse acceptée a été modifiée et son explication est devenue un peu incorrecte. L'échantillon de code a été actualisé, mais le texte ci-dessous reste le même. Vous ne pouvez pas supposer que BOOL est un caractère pour le moment car il dépend de l'architecture et de la plate-forme. Ainsi, si vous exécutez votre code sur une plate-forme 32 bits (par exemple iPhone 5) et imprimez @encode (BOOL), vous verrez "c". Cela correspond à un type char . Mais si vous exécutez votre code sur l'iPhone 5s (64 bits), vous verrez "B". Cela correspond à un type booléen .

curieuse
la source
1

Je vais contre la convention ici. Je n'aime pas les typedef aux types de base. Je pense que c'est une indirection inutile qui enlève de la valeur.

  1. Quand je verrai le type de base dans votre source, je le comprendrai instantanément. Si c'est un typedef, je dois le chercher pour voir à quoi je m'occupe vraiment.
  2. Lors du portage vers un autre compilateur ou de l'ajout d'une autre bibliothèque, leur ensemble de typedefs peut entrer en conflit et provoquer des problèmes difficiles à déboguer. Je viens juste de m'en occuper en fait. Dans une bibliothèque, boolean a été typé en entier, et dans mingw / gcc, il est typé en caractère.
Geai
la source
4
Eh bien ... on peut s'attendre à ce que vous connaissiez les typedef standard de votre langue (pensez size_t), et les deux bool(C99) et BOOL(ObjC) entrent dans cette catégorie. Et si votre code a échoué en raison d'un changement de typedef, c'est votre code à blâmer puisque vous n'avez apparemment pas traité le typedef comme une chose opaque, mais vous vous êtes appuyé sur son implémentation sur une plate-forme. (Il n'y a pas de quoi avoir honte, ça arrive, mais ce n'est pas le typedef à blâmer.)
DevSolar
1
Les typedefs "standard" ne semblent pas être très standard (par exemple pendant un certain temps MS n'a pas supporté les standards posix, etc.). Si vous n'utilisez pas de typedefs, le problème avec les typedefs changeant ou étant différents sur différents compilateurs est éliminé.
Jay
1
-1, les typedefs en général servent deux objectifs importants (entre autres): fournir une bonne sémantique et fournir une certaine mauvaise direction. Idéalement, vous ne devriez pas avoir besoin de connaître le type de base auquel un typedef se réfère, malheureusement ce système n'est pas parfait et parfois vous devez le savoir. Mon point est le suivant: vous devriez suivre la convention car même en admettant que ce n'est pas parfait, c'est mieux que l'alternative.
João Portela
2
@Jay: Désolé, j'aurais dû expliquer pourquoi cette "mauvaise direction" est bonne. Je vais essayer de donner un exemple: si vous utilisez le booléen typedef'd au lieu d'utiliser directement un int ou un caractère, vous autorisez l'utilisation d'un type différent (qui fonctionne toujours) sur chaque plate-forme sans casser votre code [raisons pour cela varie, mais nous pouvons imaginer une plate-forme où un caractère peut être mal aligné en mémoire et donc plus lent afin qu'un int puisse être utilisé pour un booléen à la place].
João Portela
2
@Jay: Par "bonne sémantique", je veux dire que lorsque vous déclarez votre booléen BOOL varnameau lieu de char varnamecela, il est plus évident que les deux valeurs valides pour cette variable sont true/ YESou false/ NO.
João Portela
1

Comme mentionné ci-dessus, il BOOLpeut s'agir d'un unsigned chartype en fonction de votre architecture, alors qu'il boolest de type int. Une expérience simple montrera la différence pourquoi BOOL et bool peuvent se comporter différemment:

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);

À votre grande surprise if(objcBOOL != YES), le compilateur évaluera à 1, car il YESs'agit en fait du code de caractère 1, et aux yeux du compilateur, le code de caractère 64 n'est bien sûr pas égal au code de caractère 1, donc l'instruction if sera évaluée àYES/true/1 et la ligne suivante sera courir. Cependant, comme un booltype aucun zéro évalue toujours la valeur entière de 1, le problème ci-dessus n'affectera pas votre code. Voici quelques bons conseils si vous souhaitez utiliser le Objective-C BOOLtype par rapport au ANSI C booltype:

  • Attribuez toujours le YESouNO valeur et rien d'autre.
  • Convertir BOOL types en utilisant double not!! opérateur pour éviter des résultats inattendus.
  • Lors de la vérification de l' YESutilisation, if(!myBool) instead of if(myBool != YES)il est beaucoup plus propre d'utiliser l' !opérateur not et donne le résultat attendu.
ilgaar
la source
1

Soyez également conscient des différences de diffusion, en particulier lorsque vous travaillez avec des masques de bits, en raison de la diffusion en caractère signé:

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

Si BOOL est un caractère signé au lieu d'un booléen, la conversion de 0x0100 en BOOL supprime simplement le bit défini et la valeur résultante est 0.

michaf
la source