Existe uma diferença entre SIM / NÃO, VERDADEIRO / FALSO e verdadeiro / falso no objetivo-c?


154

Simples pergunta realmente; existe uma diferença entre esses valores (e existe uma diferença entre BOOL e bool)? Um colega de trabalho mencionou que eles avaliam coisas diferentes no Objective-C, mas quando observei os typedefs em seus respectivos arquivos .h, YES / TRUE / true foram todos definidos como 1e NO / FALSE / false foram definidos como 0. Existe realmente alguma diferença?


5
Do ponto de vista prático, não há diferença. Provavelmente, você pode fazer vários truques para demonstrar a diferença, mas geralmente está entrando no território de "comportamento indefinido".
— Hot Licks

Respostas:


84

Não há diferença prática, desde que você use BOOLvariáveis ​​como booleanos. C processa expressões booleanas com base na avaliação de 0 ou não de 0. Portanto:

if(someVar ) { ... }
if(!someVar) { ... }

significa o mesmo que

if(someVar!=0) { ... }
if(someVar==0) { ... }

é por isso que você pode avaliar qualquer tipo ou expressão primitiva como um teste booleano (incluindo, por exemplo, ponteiros). Note que você deve fazer o primeiro, não o último.

Note que não é uma diferença se você atribuir valores obtusos a um chamado BOOLvariável e teste para valores específicos, por isso sempre usá-los como booleans e só atribuí-los a partir de seus #definevalores.

Importante, nunca teste booleanos usando uma comparação de caracteres - não é apenas arriscado, porque someVarpode ser atribuído um valor diferente de zero que não é SIM, mas, na minha opinião, o mais importante, ele falha ao expressar a intenção corretamente:

if(someVar==YES) { ... } // don't do this!
if(someVar==NO ) { ... } // don't do this either!

Em outras palavras, use construções conforme pretendidas e documentadas para serem usadas e você se poupará de um mundo de mágoas em C.


100

Eu acredito que é uma diferença entre boole BOOL, confira esta página para uma explicação do porquê:
http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

Como BOOLé um tipo em unsigned charvez de primitivo, as variáveis ​​do tipo BOOLpodem conter valores diferentes de YESe NO.

Considere este código:

BOOL b = 42;

if (b) {
    printf("b is not NO!\n");
}

if (b != YES) {
    printf("b is not YES!\n");
}

A saída é:

b não é NÃO!
b não é SIM!

Para a maioria das pessoas, essa é uma preocupação desnecessária, mas se você realmente deseja um booleano, é melhor usar a bool. Devo acrescentar: o iOS SDK geralmente usa BOOLem suas definições de interface, portanto esse é um argumento a ser seguido BOOL.


5
Mas observe que a implementação C original não tinha boole, portanto, tem sido uma tradição usar um intou charcomo um booleano, às vezes com um #define para esconder a diferença e às vezes não. De fato, não tenho certeza se mesmo os padrões atuais precisam boolser implementados de uma maneira que impeça o exame de sua estrutura interna.
— Hot Licks

1
Embora, o primeiro printfconte mentiras. O valor de bnão é YES, é "não zero", que é o que a condição testa. Então você deve ter printf("b is not zero"), que não é necessariamente o mesmo que YES. Nesse caso, bé "não zero" e "não SIM".
— Lawrence Dol

Obrigado Lawrence, fiz uma atualização nesse sentido.
— Dan J

Na verdade, eu não recebi a segunda saída no Xcode 8.2. Onde eu falho?
— Igor Kislyuk

1
@ HotLicks, não há diferença inerente entre 0, não zero e falso e verdadeiro. Desde que o valor pretenda ser um booleano lógico, ele sempre terá essa interface para preservar a compatibilidade binária. Os problemas começam quando você usa não booleanos que parecem booleanos, por exemplo, função de entrada de aplicativo de biblioteca padrão c, retornos principais 0 com êxito, muitos acabam pensando nesse 0 como um booleano, quando na verdade é uma enumeração definida pelo aplicativo ou definida pelo usuário valor, que normalmente espera que seja diferente de zero em terminação anormal.
— Dmitry

52

Eu fiz um teste exaustivo sobre isso. Meus resultados devem falar por si:

//These will all print "1"
NSLog(@"%d", true == true);
NSLog(@"%d", TRUE == true);
NSLog(@"%d", YES  == true);
NSLog(@"%d", true == TRUE);
NSLog(@"%d", TRUE == TRUE);
NSLog(@"%d", YES  == TRUE);
NSLog(@"%d", true == YES);
NSLog(@"%d", TRUE == YES);
NSLog(@"%d", YES  == YES);

NSLog(@"%d", false == false);
NSLog(@"%d", FALSE == false);
NSLog(@"%d", NO    == false);
NSLog(@"%d", false == FALSE);
NSLog(@"%d", FALSE == FALSE);
NSLog(@"%d", NO    == FALSE);
NSLog(@"%d", false == NO);
NSLog(@"%d", FALSE == NO);
NSLog(@"%d", NO    == NO);


//These will all print "0"
NSLog(@"%d", false == true);
NSLog(@"%d", FALSE == true);
NSLog(@"%d", NO    == true);
NSLog(@"%d", false == TRUE);
NSLog(@"%d", FALSE == TRUE);
NSLog(@"%d", NO    == TRUE);
NSLog(@"%d", false == YES);
NSLog(@"%d", FALSE == YES);
NSLog(@"%d", NO    == YES);

NSLog(@"%d", true == false);
NSLog(@"%d", TRUE == false);
NSLog(@"%d", YES  == false);
NSLog(@"%d", true == FALSE);
NSLog(@"%d", TRUE == FALSE);
NSLog(@"%d", YES  == FALSE);
NSLog(@"%d", true == NO);
NSLog(@"%d", TRUE == NO);
NSLog(@"%d", YES  == NO);

A saída é:

2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.072 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.076 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.082 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.091 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.092 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.097 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.098 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.101 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0

3
[[NSObject] assign] init] não é igual a VERDADEIRO ou SIM. Portanto, o teste para inicialização do objeto com if ([[NSObject] aloc]] init] == ​​TRUE) falhará. Nunca me senti à vontade com uma linguagem que defina um valor "verdadeiro" singular, quando na verdade qualquer valor diferente de zero serve.
— usar o seguinte código

3
@SamuelRenkert Eu nunca me senti confortável com um idioma que tenha um valor não-booleano em um ifou em um while. Como ... while("guitar gently weeps")não deveria funcionar ... #
— Supuhstar #

@SamuelRenkert também o backdoor Linux que foi encontrado em 2003:if (user_id = ROOT_UID)
— Supuhstar

14

Você pode querer ler as respostas para esta pergunta . Em resumo, em Objective-C (da definição em objc.h):

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


#define YES             (BOOL)1
#define NO              (BOOL)0

11

A principal diferença (perigosa!) Entre truee YESestá na serialização JSON.

Por exemplo, temos uma solicitação de servidor do tipo JSON e precisamos enviar true / false no json sence:

NSDictionary *r1 = @{@"bool" : @(true)};
NSDictionary *r2 = @{@"bool" : @(YES)};
NSDictionary *r3 = @{@"bool" : @((BOOL)true)};

Em seguida, convertemos para a string JSON antes de enviar como

NSData *data = [NSJSONSerialization  dataWithJSONObject:requestParams options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

O resultado é

jsonString1 // {"bool":1}
jsonString2 // {"bool":true}
jsonString3 // {"bool":true}

Devido à lógica da API, jsonString1pode resultar em um erro.

Portanto, tenha cuidado com os booleanos no Objective-C.

Para resumir, apenas o @YESvalor exato e convertido como @((BOOL)expression)são do __NSCFBooleantipo e convertido para truecom serialização JSON. Quaisquer outras expressões como @(expression1 && expression2)(par @(YES && YES)) são do __NSCFNumber (int)tipo e convertidas 1em JSON.

PS Você pode simplesmente usar booleano com valor de string

@{@"bool" : @"true"}; // in JSON {"bool":true}

1

Há um bug sutil que ninguém mencionou aqui, que eu pensei que incluiria ... mais um erro lógico do que qualquer coisa:

int i = 2;
if(i);        //true
if(i==YES);   // false
if((!!i)==YES); //true

portanto, a questão aqui é apenas isso (YES==1)e em C a comparação não é booleana, mas baseada em valor.

porque YESé apenas um #define(em vez de algo intrínseco à linguagem), tem que ter algum valor e 1faz mais sentido.


Esta é essencialmente a mesma resposta que a de DanJ, ​​de mais de 2 anos antes, com menos detalhes.
— Lawrence Dol

@LawrenceDol Eu não sei, ele menciona que YES é apenas # definido para ser 1 e não intrínseco ao idioma, como se estivesse em um idioma de nível superior ... alguém poderia obter valor com isso ... mas bom trollando, com você.
— Grady Player

0

Eu acho que eles adicionam SIM / NÃO para ser mais auto-explicativo em muitos casos. Por exemplo:

[button setHidden:YES];

soa melhor que

[button setHidden:TRUE];

2
Discordo; os dois leem o mesmo para mim. No entanto, em uma interface do usuário para um leigo, acho que Sim / Não parece melhor.
— Lawrence Dol

16
Eu também discordo. Na verdade, ele lê mal devido a não aderência aos padrões não escritos que são usados ​​há anos em outros idiomas. O IE é um excelente exemplo do que acontece quando você falha em seguir um grande número de padrões.
— FreeAsInBeer 21/07

1
Metade downvote para 2 respostas imprecisas e meia downvote para assinar suas respostas
— fpg1503

-2

Primeiro, vamos examinar o que é verdadeiro e falso e o que lhes dá significado em primeiro lugar.

podemos construir uma estrutura chamada if a então b else c no cálculo lambda da seguinte maneira:

(\ifThenElse. <use if then else>)(\a. \b. \c. a b c)

Em JavaScript, fica assim:

(function(ifThenElse) {
    // use ifThenElse
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
});

para que IfThenElse seja útil, precisamos de uma função "true" que escolha direita ou esquerda, e faça isso enquanto ignora a outra opção, ou de uma função "false" que escolha a opção "true".

Podemos definir essas funções da seguinte maneira:

(\true. <use true>)(\a. \b. a) and (\false. <use false>)(\a. \b. b)

em JavaScript, fica assim:

(function(True) {
    // use True
})(function(a) {
     return function(b) {
         return a;
     }
});

(function(False) {
    // use True
})(function(a) {
     return function(b) {
         return b;
     }
});

agora podemos fazer o seguinte

(\true. \false. \ifThenElse. \doThis. \doThat. ifThenElse true doThis doThat)
(\a. \b. a)(\a. \b. b)(\a. \b. \c. a b c)(\a. ())(\a. ())

sendo doThis e doThat (\ a. ()) porque o cálculo lambda não oferece nenhum serviço, como printing / math / strings, tudo o que podemos fazer é não fazer nada e dizer que fizemos (e depois trapacear substituindo-o por serviços em nosso sistema que fornece efeitos colaterais que queremos)

então vamos ver isso em ação.

(function(True) {
    return (function(False) {
        return (function(ifThenElse) {
            return (function(doThis) {
                return (function(doThat) {
                    return ifThenElse(True)(doThis)(doThat);
                });
            });
        });
    })
})(function(a) {
     return function(b) {
         return a;
     }
})(function(a) {
     return function(b) {
         return b;
     }
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
})(function(a) { console.log("you chose LEFT!"); })
(function(a) {console.log("you chose RIGHT");})();

Esse é um ambiente profundo que poderia ser simplificado se tivéssemos permissão para usar matrizes / mapas / argumentos / ou mais de uma instrução para dividir em várias funções, mas eu quero manter o mais puro possível, me limitando às funções de exatamente um argumento só.

observe que o nome Verdadeiro / Falso não tem significado inerente, podemos renomeá-los facilmente para sim / não, esquerda / direita, direita / esquerda, zero / um, maçã / laranja. Tem significado que, qualquer que seja a escolha feita, é causada apenas pelo tipo de escolha. Portanto, se "ESQUERDA" for impresso, sabemos que o seletor só pode ser verdadeiro e, com base nesse conhecimento, podemos orientar nossas decisões adicionais.

Então, para resumir

function ChooseRight(left) {
    return function _ChooseRight_inner(right) {
        return right;
    }
}
function ChooseLeft(left) {
    return function _ChooseLeft_inner(right) {
        return left;
    }
}

var env = {
    '0': ChooseLeft,
    '1': ChooseRight,
    'false': ChooseRight,
    'true': ChooseLeft,
    'no': ChooseRight
    'yes': ChooseLeft,
    'snd': ChooseRight,
    'fst': ChooseLeft
};
var _0 = env['0'];
var _1 = env['1'];
var _true = env['true'];
var _false = env['false'];
var yes = env['yes'];
var no = env['no'];

// encodes church zero or one to boolean
function lambda_encodeBoolean(self) {
    return self(false)(true);
}
// decodes a Boolean to church zero or one
function lambda_decodeBoolean(self) {
    console.log(self, self ? env['true'] : env['false']);
    return self ? env['true'] : env['false'];
}

lambda_decodeBoolean('one' === 'two')(function() {
    console.log('one is two');
})(function() {
    console.log('one is not two');
})();

lambda_decodeBoolean('one' === 'one')(function() {
    console.log('one is one');
})(function() {
    console.log('one is not one');
})();

-7

Não, SIM / NÃO é uma maneira diferente de se referir a VERDADEIRO / FALSO (1/0)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.