Objetivo-C: BOOL vs bool

192

Vi el "nuevo tipo" BOOL ( YES, NO).

Leí que este tipo es casi como un char.

Para probar lo hice:

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

Es bueno ver que ambos registros muestran "1" (a veces en C ++ bool es un int y su tamaño es 4)

¿Entonces me preguntaba si había algunos problemas con el tipo bool o algo así?

¿Puedo usar bool (que parece funcionar) sin perder velocidad?

Francescu
fuente

Respuestas:

198

De la definición en 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)

Entonces, sí, puedes asumir que BOOL es un char. Puede usar el tipo (C99) bool, pero todos los marcos Objective-C de Apple y la mayoría del código Objective-C / Cocoa usan BOOL, por lo que se ahorrará dolor de cabeza si el tipo de definición cambia alguna vez con solo usar BOOL.

Barry Wark
fuente
17
"Todos los marcos de Apple" - no es cierto. Eche un vistazo a CGGeometry.h, específicamente: CG_INLINE bool __CGPointEqualToPoint (CGPoint point1, CGPoint point2) {return point1.x == point2.x && point1.y == point2.y; }
Elliot
58
@Elliot Tienes razón. Muchos de los marcos C (CoreFoundation, CoreGraphics, etc.) usan C99 bool. Todos los marcos de Objective-C utilizan BOOL.
Barry Wark
@ Cœur ha editado la definición del ejemplo de código BOOL, pero el texto a continuación sigue siendo el mismo. Es un poco confuso y es incorrecto. Mira mi respuesta.
curioso
Conozca diferentes comportamientos eche un vistazo a continuación. NSInteger progressTime = 2;//any value NSInteger totalTime = 1;//any value BOOL success = (progressTime>=totalTime)// siempre da NO Pero una vez que recibí ese (progressTime>=totalTime)valor en booltipo success, devuelve el resultado correcto. No entiendo este comportamiento. Estoy usando Xcode 7.xy la iOSversión fue 8.x. @BarryWark
Kamar Shad
34

Como se mencionó anteriormente, BOOL es un personaje firmado. bool - tipo del estándar C99 (int).

BOOL - SÍ / NO. bool - verdadero / falso.

Ver ejemplos:

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

Y el resultado es

REAL b1
REAL b2
NO REAL b2

Tenga en cuenta que bool! = BOOL. El resultado a continuación es solo UNA VEZ MÁS - REAL b2

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

Si desea convertir bool a BOOL, debe usar el siguiente código

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

Entonces, en nuestro 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");

Y entonces ... ¿qué tenemos ahora? :-)

berilio
fuente
3
Podrías, en lugar de usar el operador ternario, usar !!b1. Para convertir entre ellos
Richard J. Ross III
1
'NOT REAL b2' no está impreso en mi simulador de iPhone SE.
charlatán
12

Al momento de escribir esta es la versión más reciente 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

Significa que en dispositivos iOS de 64 bits y en WatchOS BOOLes exactamente lo mismo que boolen todos los demás dispositivos (OS X, iOS de 32 bits) es signed chary ni siquiera puede ser anulado por el indicador del compilador-funsigned-char

También significa que este código de ejemplo se ejecutará de manera diferente en diferentes plataformas (lo probé yo mismo):

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

Por cierto, las cosas nunca asignar gusta array.counta BOOLla variable ya que aproximadamente el 0,4% de los valores posibles será negativo.

Piotr Tobolski
fuente
el compilador generará un error si usa bool como parámetro de un bloque que se define para obtener un BOOL (bloques de animación UIView, por ejemplo), cuando compila para iOS 32 bits (iPhone 5C ...). Uso C ++ bool en todas partes en mi código, y BOOL en las API que se definen con BOOL
stephane k.
8

El tipo de Objective-C que debe usar es BOOL. No hay nada como un tipo de datos booleano nativo, por lo tanto, para asegurarse de que el código se compila en todos los compiladores BOOL. (Está definido en Apple-Frameworks.

Georg Schölly
fuente
2
Esto no es estrictamente exacto. BOOLestá definido por el lenguaje Objective-C (está en uno de los objc/*.hencabezados), no por los marcos. Además, al compilar con C99 (que creo que es el predeterminado), entonces hay un tipo booleano nativo _Bool(o boolsi stdbool.hestá incluido).
dreamlax
5

Sí, BOOL es un typedef para un carácter firmado de acuerdo con objc.h.

Sin embargo, no sé sobre bool. Eso es una cosa de C ++, ¿verdad? Si se define como un carácter firmado donde 1 es SÍ / verdadero y 0 es NO / falso, entonces imagino que no importa cuál use.

Sin embargo, dado que BOOL es parte de Objective-C, probablemente tenga más sentido usar un BOOL para mayor claridad (otros desarrolladores de Objective-C podrían quedar perplejos si ven un bool en uso).

Jeff
fuente
66
_Bool se define en C99, y en el encabezado estándar stdbool.h, se define el macro bool (que se expande a _Bool) y aquí también se definen verdadero / falso.
Brian Mitchell el
4

Otra diferencia entre bool y BOOL es que no se convierten exactamente al mismo tipo de objetos, cuando observas valores-clave, o cuando usas métodos como - [NSObject valueForKey:].

Como todos han dicho aquí, BOOL es char. Como tal, se convierte en un NSNumber con un carácter. Este objeto no se puede distinguir de un NSNumber creado a partir de un carácter normal como 'A' o '\ 0'. Has perdido totalmente la información de que originalmente tenías un BOOL.

Sin embargo, bool se convierte en un CFBoolean, que se comporta igual que NSNumber, pero que conserva el origen booleano del objeto.

No creo que este sea un argumento en un debate BOOL vs. bool, pero esto puede morderte algún día.

En términos generales, debe usar BOOL, ya que este es el tipo utilizado en todas partes en las API de Cocoa / iOS (diseñado antes de C99 y su tipo de bool nativo).

Gwendal Roué
fuente
2

La respuesta aceptada ha sido editada y su explicación se volvió un poco incorrecta. El ejemplo de código se ha actualizado, pero el texto a continuación permanece igual. No puede suponer que BOOL es un char por ahora, ya que depende de la arquitectura y la plataforma. Por lo tanto, si ejecuta su código en la plataforma de 32 bits (por ejemplo, iPhone 5) e imprime @encode (BOOL) verá "c". Corresponde a un tipo char . Pero si ejecuta su código en el iPhone 5s (64 bits) verá "B". Corresponde a un tipo bool .

curioso
fuente
1

Voy en contra de la convención aquí. No me gusta typedef's a los tipos base. Creo que es una indirección inútil que elimina el valor.

  1. Cuando vea el tipo base en su fuente, lo entenderé al instante. Si es un typedef, tengo que buscarlo para ver con qué estoy realmente tratando.
  2. Al portar a otro compilador o agregar otra biblioteca, su conjunto de typedefs puede entrar en conflicto y causar problemas que son difíciles de depurar. Acabo de terminar lidiando con esto, de hecho. En una biblioteca, boolean se definió como int, y en mingw / gcc se definió como char.
Arrendajo
fuente
44
Bueno ... puede esperará a conocer el typedef estándar es de su idioma (piensa size_t), y ambos bool(C99) y BOOLotoño (ObjC) en esa categoría. Y si su código falló debido a un cambio de typedef, es su código el culpable, ya que aparentemente no manejó el typedef como algo opaco, sino que confió en su implementación en una plataforma. (Nada de lo que avergonzarse, sucede, pero no es el culpable de typedef.)
DevSolar
1
Los typedefs "estándar" no parecen ser muy estándar (por ejemplo, por un tiempo, MS no admitió estándares posix, etc.). Si no usa typedefs, entonces se elimina el problema de que typedefs cambie o sea diferente en diferentes compiladores.
Jay
1
-1, typedefs en general tiene dos propósitos importantes (entre otros): proporcionar una buena semántica y proporcionar una mala dirección. Idealmente, no debería necesitar saber el tipo base al que se refiere typedef, desafortunadamente este sistema no es perfecto y, a veces, debe saberlo. Mi punto es: debes seguir la convención porque incluso admitir que no es perfecto es mejor que la alternativa.
João Portela
2
@ Jay: Lo siento, debería haber explicado por qué esta "mala dirección" es buena. Intentaré proporcionar un ejemplo: si usa el booleano typedef'd en lugar de usar un int o un char directamente, está permitiendo que se use un tipo diferente (que todavía funciona) en cada plataforma sin romper su código [razones para esto varía, pero podemos imaginar una plataforma en la que un carácter puede estar desalineado en la memoria y, por lo tanto, más lento, por lo que se puede utilizar un int para un valor booleano].
João Portela
2
@ Jay: Por "buena semántica" quiero decir que cuando declaras tu booleano en BOOL varnamelugar de char varnameesto, es más obvio que los dos valores válidos para esa variable son true/ YESo false/ NO.
João Portela
1

Como se mencionó anteriormente, BOOLpodría ser un unsigned chartipo dependiendo de su arquitectura, mientras que booles de tipo int. Un experimento simple mostrará la diferencia por qué BOOL y bool pueden comportarse de manera diferente:

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

Para su sorpresa if(objcBOOL != YES), el compilador evaluará a 1, ya YESque en realidad es el código de caracteres 1, y a los ojos del compilador, el código de caracteres 64 no es, por supuesto, igual al código de caracteres 1, por lo tanto, la instrucción if se evaluará YES/true/1y la siguiente línea será correr. Sin embargo, dado que un booltipo distinto de cero siempre se evalúa como el valor entero de 1, el problema anterior no afectará su código. A continuación se presentan algunos buenos consejos si desea utilizar el Objective-C BOOLtipo frente al ANSI C booltipo:

  • Asigne siempre el valor YESo NOy nada más.
  • Convierta los BOOLtipos utilizando el !!operador doble no para evitar resultados inesperados.
  • Cuando se verifica el YESuso if(!myBool) instead of if(myBool != YES), es mucho más limpio usar el !operador no y da el resultado esperado.
ilgaar
fuente
1

Además, tenga en cuenta las diferencias en la conversión, especialmente cuando trabaje con máscaras de bits, debido a la conversión a caracteres firmados:

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 es un carácter firmado en lugar de un bool, el reparto de 0x0100 a BOOL simplemente deja caer el bit establecido y el valor resultante es 0.

michaf
fuente