Obiettivo-C: BOOL vs bool


192

Ho visto il "nuovo tipo" BOOL( YES, NO).

Ho letto che questo tipo è quasi come un personaggio.

Per i test ho fatto:

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

È bello vedere che entrambi i registri visualizzano "1" (a volte in C ++ bool è un int e la sua dimensione è 4)

Quindi mi stavo solo chiedendo se ci fossero dei problemi con il tipo di bool o qualcosa del genere?

Posso semplicemente usare Bool (che sembra funzionare) senza perdere velocità?

Risposte:


199

Dalla definizione 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)

Quindi, sì, puoi presumere che BOOL sia un personaggio. Puoi usare il tipo (C99) bool, ma tutti i framework Objective-C di Apple e la maggior parte del codice Objective-C / Cocoa usano BOOL, così ti risparmierai mal di testa se il typedef cambia mai usando semplicemente BOOL.


17
"tutti i framework di Apple" - non è vero. Dai un'occhiata a CGGeometry.h, in particolare: CG_INLINE bool __CGPointEqualToPoint (CGPoint point1, CGPoint point2) {return point1.x == point2.x && point1.y == point2.y; }
Elliot,

58
@Elliot Hai ragione. Molti dei framework C (CoreFoundation, CoreGraphics, ecc.) Usano C99 bool. Tutti i framework Objective-C utilizzano BOOL.
Barry Wark,

@ Cœur hai modificato la definizione di esempio di codice BOOL, ma il testo seguente rimane lo stesso. È un po 'confuso ed è errato. Vedi la mia risposta
curioso

Conosci diversi comportamenti, dai un'occhiata qui sotto. NSInteger progressTime = 2;//any value NSInteger totalTime = 1;//any value BOOL success = (progressTime>=totalTime)// dà sempre, NO ma una volta ricevuto quel (progressTime>=totalTime)valore nel booltipo successrestituisce il risultato corretto. Non capisco questo comportamento. Sto usando Xcode 7.xe la iOSversione era 8.x. @BarryWark
Kamar Shad,

34

Come accennato in precedenza, BOOL è un carattere firmato. bool - tipo dallo standard C99 (int).

BOOL - SÌ / NO. bool: vero / falso.

Vedi esempi:

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

E il risultato è

REAL b1
REAL b2
NON REAL b2

Nota che bool! = BOOL. Il risultato sotto è DI NUOVO UNA VOLTA - REAL b2

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

Se vuoi convertire bool in BOOL devi usare il codice successivo

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

Quindi, nel nostro caso:

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

E quindi .. cosa otteniamo ora? :-)


3
È possibile, invece di utilizzare l'operatore ternario !!b1. Per convertire tra loro
Richard J. Ross III,

1
'NOT REAL b2' non è stampato sul mio simulatore iPhone SE.
gabbler

12

Al momento in cui scrivo questa è la versione più recente di 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

Significa che sui dispositivi iOS a 64 bit e su WatchOS BOOLè esattamente la stessa cosa che boolsu tutti gli altri dispositivi (OS X, iOS a 32 bit) signed chare non può nemmeno essere sovrascritto dal flag del compilatore-funsigned-char

Significa anche che questo codice di esempio verrà eseguito in modo diverso su piattaforme diverse (testato io stesso):

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

BTW non assegna mai cose come array.counta BOOLvariabili perché circa lo 0,4% dei possibili valori sarà negativo.


il compilatore genererà un errore se usi bool come parametro di un blocco definito per ottenere un BOOL (blocchi di animazione UIView, ad esempio), quando compili per iOS 32 bit (iPhone 5C ...). Uso C ++ bool ovunque nel mio codice e BOOL nelle API definite con BOOL
stephane k.

8

Il tipo Objective-C che dovresti usare è BOOL. Non c'è niente come un tipo di dati booleano nativo, quindi per essere sicuri che il codice venga compilato su tutti i compilatori BOOL. (È definito in Apple-Frameworks.


2
Questo non è rigorosamente preciso. BOOLè definito dal linguaggio Objective-C (è in una delle objc/*.hintestazioni), non dai framework. Inoltre, durante la compilazione con C99 (che credo sia l'impostazione predefinita), esiste un tipo booleano nativo _Bool(o boolse stdbool.hè incluso).
dreamlax,

5

Sì, BOOL è un typedef per un carattere firmato secondo objc.h.

Non so di bool, però. Questa è una cosa C ++, giusto? Se è definito come un carattere con segno in cui 1 è SÌ / vero e 0 è NO / falso, allora immagino che non importa quale usi.

Poiché BOOL fa parte di Objective-C, tuttavia, probabilmente ha più senso utilizzare un BOOL per chiarezza (altri sviluppatori di Objective-C potrebbero essere perplessi se vedono un bool in uso).


6
_Bool è definito in C99 e nell'intestazione standard stdbool.h viene definito il macro bool (che si espande in _Bool) e qui vengono definiti anche true / false.
Brian Mitchell,

4

Un'altra differenza tra bool e BOOL è che non si convertono esattamente nello stesso tipo di oggetti, quando si fa l'osservazione del valore-chiave o quando si usano metodi come - [NSObject valueForKey:].

Come tutti hanno detto qui, BOOL è char. Come tale, viene convertito in un NSNumber che contiene un carattere. Questo oggetto non è distinguibile da un NSNumber creato da un carattere normale come 'A' o '\ 0'. Hai completamente perso le informazioni che originariamente avevi un BOOL.

Tuttavia, bool viene convertito in un CFBoolean, che si comporta come NSNumber, ma che conserva l'origine booleana dell'oggetto.

Non penso che questo sia un argomento in un dibattito BOOL vs. bool, ma un giorno potrebbe morderti.

In generale, dovresti andare con BOOL, poiché questo è il tipo usato ovunque nelle API Cocoa / iOS (progettato prima di C99 e del suo tipo bool nativo).


2

La risposta accettata è stata modificata e la sua spiegazione diventa un po 'errata. L'esempio di codice è stato aggiornato, ma il testo seguente rimane lo stesso. Non puoi supporre che BOOL sia un char per ora poiché dipende dall'architettura e dalla piattaforma. Pertanto, se esegui il codice su piattaforma a 32 bit (ad esempio iPhone 5) e stampa @encode (BOOL) vedrai "c". Corrisponde a un tipo di carattere . Ma se esegui il tuo codice su iPhone 5s (64 bit) vedrai "B". Corrisponde a un tipo di bool .


1

Vado contro le convenzioni qui. Non mi piacciono i typedef ai tipi base. Penso che sia un inutile riferimento indiretto che rimuove il valore.

  1. Quando vedo il tipo di base nella tua fonte lo capirò immediatamente. Se è un errore di battitura, devo cercarlo per vedere con cosa ho davvero a che fare.
  2. Quando si esegue il porting su un altro compilatore o si aggiunge un'altra libreria, la loro serie di typedef potrebbe essere in conflitto e causare problemi difficili da eseguire il debug. In effetti, ho appena finito di occuparmene. In una libreria booleano è stato digitato in int, e in mingw / gcc è tipizzato in un carattere.

4
Beh ... si può essere richiesta la conoscenza dei typedef di serie è di lingua (si pensi size_t), ed entrambi bool(C99) e BOOLla caduta (objC) in quella categoria. E se il tuo codice fallisce a causa di un cambio di typedef, è colpa del tuo codice poiché apparentemente non hai gestito il typedef come una cosa opaca ma ti sei affidato alla sua implementazione su una piattaforma. (Non c'è nulla di cui vergognarsi, succede, ma non è la colpa da
scrivere a causa di errori di battitura

1
I typedef "standard" non sembrano essere molto standard (ad esempio per un certo periodo di tempo la SM non supportava gli standard posix, ecc.). Se non usi i typedef, il problema con i typedef che cambiano o sono diversi su diversi compilatori viene eliminato.
Jay,

1
-1, i dattiloscritti in generale servono a due scopi importanti (tra gli altri): fornire una buona semantica e fornire alcune indicazioni errate. Idealmente non dovresti avere bisogno di conoscere il tipo di base a cui fa riferimento un typedef, sfortunatamente questo sistema non è perfetto e talvolta devi saperlo. Il mio punto è: dovresti seguire la convenzione perché anche ammettere che non è perfetto è meglio dell'alternativa.
João Portela,

2
@Jay: mi dispiace, avrei dovuto spiegare perché questo "errore di direzione" è buono. Proverò a fornire un esempio: se usi il booleano typedef'd invece di usare direttamente un int o un carattere stai permettendo a un tipo diverso (che funziona ancora) di essere usato su ciascuna piattaforma senza rompere il tuo codice [motivi per questo varia ma possiamo immaginare una piattaforma in cui un carattere può essere disallineato in memoria e quindi più lento, quindi un int può essere usato invece per un valore booleano].
João Portela,

2
@Jay: Per "buona semantica" intendo che quando dichiari il tuo booleano BOOL varnameinvece di char varnameè più ovvio che i due valori validi per quella variabile sono true/ YESo false/ NO.
João Portela,

1

Come accennato in precedenza BOOLpotrebbe essere un unsigned chartipo a seconda della tua architettura, mentre boolè di tipo int. Un semplice esperimento mostrerà la differenza perché BOOL e bool possono comportarsi diversamente:

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

Con tua sorpresa if(objcBOOL != YES)valuterà 1 dal compilatore, poiché in YESrealtà è il codice carattere 1, e agli occhi del compilatore, il codice carattere 64 non è ovviamente uguale al codice carattere 1, quindi l'istruzione if verrà valutata YES/true/1e la riga seguente sarà correre. Tuttavia, poiché un booltipo nessuno zero restituisce sempre il valore intero 1, il problema sopra riportato non avrà effetto sul codice. Di seguito sono riportati alcuni suggerimenti utili se si desidera utilizzare il Objective-C BOOLtipo rispetto al ANSI C booltipo:

  • Assegna sempre il valore YESo NOe nient'altro.
  • Converti i BOOLtipi usando double not !!operator per evitare risultati imprevisti.
  • Quando si controlla l' YESuso if(!myBool) instead of if(myBool != YES), è molto più pulito utilizzare l' !operatore non e si ottiene il risultato previsto.

1

Inoltre, fai attenzione alle differenze nel casting, specialmente quando lavori con maschere di bit, a causa del casting con caratteri firmati:

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

Se BOOL è un carattere con segno anziché un valore booleano, il cast di 0x0100 su BOOL rilascia semplicemente il bit impostato e il valore risultante è 0.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.