Objetivo-C: BOOL vs bool

192

Eu vi o "novo tipo" BOOL( YES, NO).

Eu li que esse tipo é quase como um char.

Para testar eu fiz:

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

É bom ver que os dois logs exibem "1" (às vezes, no C ++ bool, é um int e seu tamanho é 4)

Então, eu só estava me perguntando se havia algum problema com o tipo bool ou algo assim?

Posso apenas usar bool (que parece funcionar) sem perder velocidade?

Francescu
fonte

Respostas:

198

A partir da definição em 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)

Então, sim, você pode assumir que BOOL é um caractere. Você pode usar o booltipo (C99) , mas todas as estruturas de Objective-C da Apple e a maioria dos códigos de Objective-C / Cocoa usam BOOL, portanto, você terá dor de cabeça se o typedef mudar apenas usando BOOL.

Barry Wark
fonte
17
"todos os quadros da Apple" - não é verdade. Dê uma olhada em CGGeometry.h, especificamente: CG_INLINE bool __CGPointEqualToPoint (CGPoint point1, CGPoint point2) {return point1.x == point2.x && point1.y == point2.y; }
Elliot
58
@ Elliot Você está correto. Muitas das estruturas C (CoreFoundation, CoreGraphics, etc.) usam C99 bool. Todas as estruturas de Objective-C usam BOOL.
Barry Wark
@ Você editou a definição de amostra de código BOOL, mas o texto abaixo permanece o mesmo. É um pouco confuso e está incorreto. Veja minha resposta.
curioso
Para conhecer comportamentos diferentes, dê uma olhada abaixo. NSInteger progressTime = 2;//any value NSInteger totalTime = 1;//any value BOOL success = (progressTime>=totalTime)// é sempre dá NO Mas Depois que recebi esse (progressTime>=totalTime)valor no booltipo, successele retorna o resultado correto. Eu não entendo esse comportamento. Estou usando Xcode 7.xe a iOSversão era 8.x. @BarryWark
Kamar Shad
34

Como mencionado acima, BOOL é um caractere assinado. tipo bool do padrão C99 (int).

BOOL - SIM / NÃO. bool - verdadeiro / falso.

Veja exemplos:

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 o resultado é

REAL b1
REAL b2
NÃO REAL b2

Observe que bool! = BOOL. O resultado abaixo é apenas UMA VEZ DE NOVO - REAL b2

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

Se você deseja converter bool para BOOL, use o próximo código

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

Então, no nosso 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 então .. o que temos agora? :-)

berílio
fonte
3
Você poderia, em vez de usar o operador ternário, usar !!b1. Para converter entre eles
Richard J. Ross III
1
'NOT REAL b2' não é impresso no meu simulador do iPhone SE.
tagarela
12

No momento da redação, esta é a versão mais recente do 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

Isso significa que em dispositivos iOS de 64 bits e no WatchOS BOOLé exatamente a mesma coisa que boolem todos os outros dispositivos (OS X, iOS de 32 bits), é signed chare nem pode ser substituído pelo sinalizador do compilador-funsigned-char

Isso também significa que esse código de exemplo será executado de maneira diferente em plataformas diferentes (eu mesmo testei):

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

BTW nunca atribui coisas como array.counta BOOLvariável porque cerca de 0,4% dos valores possíveis serão negativos.

Piotr Tobolski
fonte
o compilador gerará um erro se você usar bool como parâmetro de um bloco definido para obter um BOOL (blocos de animação UIView, por exemplo), ao compilar para iOS 32 bits (iPhone 5C ...). Eu uso booleano C ++ em qualquer lugar do meu código e BOOL nas APIs definidas com BOOL
stephane k.
8

O tipo de Objective-C que você deve usar é BOOL. Não há nada como um tipo de dados booleano nativo, portanto, para garantir que o código seja compilado em todos os compiladores BOOL. (Ele é definido nos frameworks da Apple.

Georg Schölly
fonte
2
Isso não é estritamente preciso. BOOLé definido pela linguagem Objective-C (está em um dos objc/*.hcabeçalhos), não pelas estruturas. Além disso, ao compilar com o C99 (que eu acho que é o padrão), existe um tipo booleano nativo _Bool(ou boolse stdbool.hestiver incluído).
dreamlax
5

Sim, BOOL é um typedef para um caractere assinado de acordo com objc.h.

Eu não sei sobre bool, no entanto. Isso é uma coisa de C ++, certo? Se for definido como um caractere assinado, onde 1 é SIM / verdadeiro e 0 é NÃO / falso, imagino que não importa qual deles você usa.

Porém, como o BOOL faz parte do Objective-C, provavelmente faz mais sentido usar um BOOL para maior clareza (outros desenvolvedores do Objective-C podem ficar intrigados se virem um bool em uso).

Jeff
fonte
6
_Bool é definido em C99, e no cabeçalho padrão stdbool.h, o macro bool é definido (que se expande para _Bool) e true / false também são definidos aqui.
Brian Mitchell
4

Outra diferença entre bool e BOOL é que eles não são convertidos exatamente para o mesmo tipo de objetos, quando você faz observação de valores-chave ou quando usa métodos como - [NSObject valueForKey:].

Como todos disseram aqui, BOOL é char. Como tal, é convertido em um NSNumber com um caractere. Este objeto é indistinguível de um NSNumber criado a partir de um caractere regular como 'A' ou '\ 0'. Você perdeu totalmente as informações que originalmente possuía um BOOL.

No entanto, bool é convertido em um CFBoolean, que se comporta da mesma forma que NSNumber, mas que mantém a origem booleana do objeto.

Eu não acho que isso seja um argumento em um debate BOOL vs. bool, mas isso pode te morder um dia.

De um modo geral, você deve usar o BOOL, pois esse é o tipo usado em qualquer lugar nas APIs do Cocoa / iOS (projetadas antes da C99 e de seu tipo bool nativo).

Gwendal Roué
fonte
2

A resposta aceita foi editada e sua explicação se tornou um pouco incorreta. O exemplo de código foi atualizado, mas o texto abaixo permanece o mesmo. Você não pode assumir que o BOOL é um caractere por enquanto, pois depende da arquitetura e da plataforma. Portanto, se você executar o código na plataforma de 32 bits (por exemplo, iPhone 5) e imprimir @encode (BOOL), verá "c". Corresponde a um tipo de caractere . Mas se você executar o código no iPhone 5s (64 bits), verá "B". Corresponde a um tipo de bool .

curioso
fonte
1

Eu vou contra a convenção aqui. Eu não gosto de typedef para tipos de base. Eu acho que é um indireto inútil que remove valor.

  1. Quando vir o tipo de base na sua fonte, entenderei instantaneamente. Se for um typedef, tenho que procurar para ver com o que realmente estou lidando.
  2. Ao portar para outro compilador ou adicionar outra biblioteca, o conjunto de typedefs pode entrar em conflito e causar problemas difíceis de depurar. Acabei de lidar com isso de fato. Em uma biblioteca, o booleano foi digitado como int e, em mingw / gcc, foi digitado como um caractere.
Jay
fonte
4
Bem ... pode- se esperar que você conheça os typedef padrão do seu idioma (pense size_t), e ambos bool(C99) e BOOL(ObjC) se enquadram nessa categoria. E se o seu código falhou devido a uma alteração no typedef, é o seu código culpado, pois você aparentemente não tratou o typedef como algo opaco, mas confiou na implementação em uma plataforma. (Nada para se envergonhar, isso acontece, mas não é o typedef a culpa.)
DevSolar
1
Os typedefs "padrão" não parecem muito padronizados (por exemplo, durante algum tempo o MS não suportava os padrões posix, etc.). Se você não usar os typedefs, o problema com os typedefs mudando ou sendo diferente em diferentes compiladores será eliminado.
Jay
1
-1, typedefs em geral servem a dois propósitos importantes (entre outros): fornecer boa semântica e fornecer alguma orientação incorreta. Idealmente, você não precisa saber o tipo de base a que um typedef se refere, infelizmente esse sistema não é perfeito e, às vezes, você precisa saber. O que quero dizer é: você deve seguir a convenção porque, mesmo admitindo que não é perfeito, é melhor que a alternativa.
João Portela
2
@ Jay: Desculpe, eu deveria ter explicado por que esse "desvio" é bom. Vou tentar fornecer um exemplo: se você usar o booleano digitado em vez de usar um int ou um char diretamente, estará permitindo que um tipo diferente (que ainda funcione) seja usado em cada plataforma sem quebrar seu código [razões para isso varia, mas podemos imaginar uma plataforma onde um caractere pode estar desalinhado na memória e, portanto, mais lento, de modo que um int possa ser usado para um booleano].
João Portela
2
@ Jay: Por "boa semântica", quero dizer que quando você declara seu booleano, em BOOL varnamevez disso char varname, é mais óbvio que os dois valores válidos para essa variável são true/ YESou false/ NO.
João Portela
1

Como mencionado acima, BOOLpode ser um unsigned chartipo, dependendo da sua arquitetura, enquanto boolé do tipo int. Uma experiência simples mostrará a diferença por que BOOL e bool podem se comportar de maneira 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 sua surpresa if(objcBOOL != YES), o 1 será avaliado pelo compilador, uma vez que, YESna verdade , é o código de caractere 1 e, aos olhos do compilador, o código de caractere 64 não é, obviamente, igual ao código de caractere 1, portanto, a instrução if será avaliada comoYES/true/1 e a linha a seguir será corre. No entanto, como um booltipo nenhum zero avalia sempre o valor inteiro 1, o problema acima não afetará seu código. Abaixo estão algumas boas dicas se você deseja usar o Objective-C BOOLtipo versus o ANSI C booltipo:

  • Sempre atribua o valor YESou NOnada mais.
  • Converter BOOL tipos usando o !!operador double not para evitar resultados inesperados.
  • Ao verificar o YESuso if(!myBool) instead of if(myBool != YES), é muito mais limpo usar o !operador not e fornece o resultado esperado.
ilgaar
fonte
1

Além disso, esteja ciente das diferenças de conversão, especialmente ao trabalhar com máscaras, devido à conversão para char assinado:

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 for um caractere assinado em vez de um bool, a conversão de 0x0100 para BOOL simplesmente reduz o bit definido e o valor resultante é 0.

michaf
fonte