2010-09-30 15 views
8

El otro día, un usuario me informó sobre un error en la barra de herramientas que se deshabilitó cuando debería haberse habilitado. El código de validación (simplificado para su beneficio) parecía:¿Por qué un BOOL es un char firmado?

- (BOOL) validateToolbarItem: (NSToolbarItem *) toolbarItem { 

    NSArray* someArray = /* arrray from somewhere*/ 

    return [someArray count]; 
} 

Me tomó unos minutos para darse cuenta de que -count devuelve un entero sin signo de 32 bits, mientras que BOOL es un carbón de 8 bits. Dio la casualidad de que en este caso someArray tenía 768 elementos, lo que significaba que los 8 bits inferiores eran todos 0. Cuando el int se envía a BOOL al regresar, se resuelve en NO, aunque un humano esperaría la respuesta ser YES.

Desde entonces, he cambiado mi código para return [someArray count] > 0; sin embargo, ahora tengo curiosidad por qué es realmente un BOOL signed char. ¿Es eso realmente "mejor" de alguna forma que una int?

+1

A menudo verá '!! [someArray count]' por exactamente esta razón (hace casi lo mismo que '> 0') – cobbal

+1

Si piensa en su pregunta un poco más, verá que es más o menos equivalente a "¿Por qué * cualquier tipo * no es lo mismo que un int?" Porque las respuestas son más o menos las mismas. Los tipos escalares más pequeños están ahí porque no requieren el rango completo de un int. BOOL ni siquiera requiere la gama completa de un char firmado, pero no había ningún tipo más pequeño disponible. – Chuck

+0

No debería asignar nada más que el resultado de expresiones booleanas a variables booleanas, sin importar qué tipo real se use para implementar variables booleanas. Revisa tu código para ver otras abominaciones como esta. – Sven

Respuesta

0

Es más pequeño, eso es todo.

2

Una respuesta obvia es que es cuatro veces más pequeño (en típicas arquitecturas de 32 bits y 64 bits), y también no tiene ningún requisito de alineación.

+0

La ironía es que en la mayoría de los compiladores/arquitecturas, rellenará los otros 3 bytes para que pueda escribir mucho más rápido 32 bits de lectura/escritura –

+0

@Paul: nunca he visto ningún compilador 'char' en las estructuras - ¿Puede dar un ejemplo? Ciertamente no lo hará en matrices debido a requisitos de almacenamiento contiguos. –

+0

struct x {int a; char b; int c; }; sizeof (x) == 12. Eso es probablemente a lo que se refiere. –

1

Un valor booleano requiere solo un bit (0 o 1), sin embargo, los sistemas estándar tratan con bytes como la unidad más pequeña. Un bool representado como un byte, en 8 bits, es 4 veces más pequeño que un entero de 32 bits, por lo tanto, la motivación para el byte sobre el entero.

1

Los bools son útiles para ahorrar un poco de espacio y restringir el valor a 0 o 1. Es un tipo más pequeño por la misma razón que puede usar un flotador sobre un doble, o un corto sobre un largo. Solo preocupaciones de espacio.

Es por eso que es una buena idea ser explícito con su conversión, y en el caso de un valor booleano, realizar una comparación lógica real entre dos del mismo tipo para obtener un bool real en lugar de un valor truncado.

4

Retroceso a tiempos más simples.

El tipo BOOL fue creado atrás cuando trabajó de forma natural con las CPU de 8 bits tipos, rara vez relleno para 16 o 32 bits. Sin embargo, la memoria era escasa y meter 1 bit en 4 bytes en realidad comería un pedazo notable de memoria adicional.

Tenga en cuenta que BOOL probablemente es anterior a _bool de C++ por bastante tiempo (iirc-- pueden tener más o menos la misma edad. Cuando NeXT eligió Objective-C, C++ tenía casi la misma popularidad).

12

Las respuestas dadas enfoque (hasta ahora) sobre por qué BOOL no es un int. Esa respuesta es bastante clara: un char es más pequeño que un int, y cuando Objective-C se diseñó en los años 80, eliminar algunos bytes siempre fue bueno.

Pero su pregunta también parece estar preguntando: "¿Por qué es BOOL firmado en vez de sin firmar?" Por eso, podemos ver donde se typedef'ed BOOL, en /usr/include/objc/objc.h:

typedef signed char  BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used. 

Así que hay una respuesta: los diseñadores de Objective-C no querían typedef BOOL a char, porque en algunos sistemas, bajo alguna compiladores (y recuerde que Objective-C es anterior a ANSI C, por lo que los compiladores de C difieren), se ha firmado un carácter y, en algunos casos, no se ha firmado. Los diseñadores querían que @encode(BOOL) devolvieran un valor constante en todas las plataformas, por lo que incluían la firma en el typedef.

Pero eso plantea la pregunta: ¿por qué en lugar de firmado sin firmar?No tengo una respuesta definitiva para eso; Me imagino que la razón es que tuvieron que elegir una u otra y decidieron firmar. Si tuviera que hacer más conjeturas, diría que es porque las entradas están firmadas por defecto (es decir, si no incluyen un calificador de firma).

+0

Si no hay ninguna lógica detrás de la escena, entonces esta no es una decisión lógica. ¿Sin respuesta? Eso es malo en ciencias formales. La aleatoriedad no debería aplicarse a las decisiones de diseño. Especialmente cuando se diseñan lenguajes formales. ¿Moralidad? No sé. Pero parece legítimo preguntarse si O-C es un lenguaje digno, entonces. – cedbeu

+0

@cedbeu: ¿Qué te hace decir que hay * no * lógica? Hay mucha lógica sobre por qué 'BOOL' es un' char' de algún tipo. Lo único que no está claro es por qué está firmado en lugar de sin firmar, cualquiera de los cuales es bastante arbitrario en esta circunstancia (lo que significa que tiene que elegir uno, pero no es gran cosa, cuál es elegido). – mipadi

+0

cierto. Solo, no me gusta la idea. Yo tendería a pensar que si tiene que tomar una decisión arbitraria, incluso menor, significa que hay algunos defectos en el diseño del núcleo. Pero tienes razón, probablemente no sea un gran problema, y ​​probablemente existen decisiones de diseño arbitrarias en algún momento en cada lengua (brrr). – cedbeu

Cuestiones relacionadas