C'è una differenza tra SÌ / NO, VERO / FALSO e vero / falso in obiettivo-c?


154

Domanda semplice davvero; c'è una differenza tra questi valori (e c'è una differenza tra BOOL e bool)? Un collega ha detto che valutano cose diverse in Objective-C, ma quando ho guardato i typedef nei rispettivi file .h, YES / TRUE / true sono stati tutti definiti come 1e NO / FALSE / false sono stati tutti definiti come 0. C'è davvero qualche differenza?


5
Da un punto di vista pratico non c'è differenza. Probabilmente puoi fare vari trucchi per dimostrare la differenza, ma in genere ti perdi nel territorio del "comportamento indefinito".
Hot Licks

Risposte:


84

Non ci sono differenze pratiche a condizione che tu usi le BOOLvariabili come booleane. C elabora le espressioni booleane in base alla valutazione a 0 o meno 0. Quindi:

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

significa lo stesso di

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

ecco perché puoi valutare qualsiasi tipo o espressione primitiva come test booleano (inclusi, ad esempio, i puntatori). Nota che dovresti fare il primo, non il secondo.

Si noti che ci sia una differenza se si assegna valori ottusi ad una cosiddetta BOOLvariabile e prova per i valori specifici, in modo sempre usarli come booleani e solo assegnarli dai loro #definevalori.

È importante sottolineare che non testare mai i booleani usando un confronto di caratteri - non è solo rischioso perché someVarpotrebbe essere assegnato un valore diverso da zero che non è SÌ, ma, a mio avviso, soprattutto, non riesce a esprimere correttamente l'intento:

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

In altre parole, usa i costrutti come sono previsti e documentati per essere usati e ti risparmierai da un mondo di ferite in C.


100

Credo che ci sia una differenza tra boole BOOL, controlla questa pagina web per una spiegazione del perché:
http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

Poiché BOOLè un tipo unsigned charpiuttosto che un tipo primitivo, le variabili di tipo BOOLpossono contenere valori diversi da YESe NO.

Considera questo codice:

BOOL b = 42;

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

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

L'output è:

b non è NO!
b non è SÌ!

Per la maggior parte delle persone questa è una preoccupazione non necessaria, ma se vuoi davvero un booleano è meglio usare a bool. Dovrei aggiungere: l'SDK di iOS generalmente utilizza BOOLle definizioni dell'interfaccia, quindi è un argomento su cui attenersi BOOL.


5
Ma nota che l'implementazione C originale non aveva bool, e quindi è stata la tradizione usare un into charcome un booleano, a volte con un #define per nascondere la differenza e altre volte no. In effetti, non sono sicuro se anche gli standard attuali debbano boolessere implementati in un modo che impedisce di esaminarne la struttura interna.
Hot Licks

1
Anche se, il primo printfracconta bugie. Il valore di bnon è YES, è "non zero", che è ciò che la condizione verifica. Quindi dovresti avere printf("b is not zero"), che non è necessariamente lo stesso di YES. In questo caso, bè sia "non zero" che "non SÌ".
Lawrence Dol,

Grazie Lawrence, ho fatto un aggiornamento in tal senso.
Dan J

In effetti, non ho ottenuto il secondo output in Xcode 8.2. Dove fallisco?
Igor Kislyuk,

1
@HotLicks non c'è alcuna differenza intrinseca tra 0, non zero, falso e vero. Finché il valore deve essere un valore booleano logico, avrà sempre questa interfaccia al fine di preservare la compatibilità binaria. I problemi iniziano quando si utilizzano booleani che sembrano booleani, ad esempio c funzione di immissione dell'applicazione libreria standard, ritorni principali 0 in caso di successo, molti finiscono per pensare a questo 0 come un booleano, quando in realtà si tratta di un elenco definito dall'applicazione o definito dall'utente valore, che spesso le calle si aspettano essere diverso da zero in caso di interruzione anomala.
Dmitry

52

Ho fatto un test esauriente su questo. I miei risultati dovrebbero parlare da soli:

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

L'output è:

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] alloc] init] non è uguale a TRUE o YES. Quindi il test per l'inizializzazione dell'oggetto con if ([[NSObject] alloc] init] == ​​TRUE) fallirà. Non mi sono mai trovato a mio agio con una lingua che definisce un singolare valore "vero" quando in realtà qualsiasi valore diverso da zero lo farà.
DrFloyd5,

3
@SamuelRenkert Non mi sono mai trovato a mio agio con una lingua che assume un valore non booleano in a ifo a while. Come ... while("guitar gently weeps")non dovrebbe funzionare ...
Supuhstar

@SamuelRenkert anche la backdoor di Linux che è stata trovata nel 2003:if (user_id = ROOT_UID)
Supuhstar il

14

Potresti voler leggere le risposte a questa domanda . In sintesi, in Objective-C (dalla definizione in 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

La differenza principale (pericolosa!) Tra truee YESè nella serializzazione JSON.

Ad esempio, abbiamo una richiesta del server di tipo JSON e dobbiamo inviare true / false in json sence:

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

Quindi lo convertiamo in stringa JSON prima di inviarlo come

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

Il risultato è

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

A causa della logica dell'API, jsonString1potrebbe verificarsi un errore.

Quindi fai attenzione ai booleani in Objective-C.

Per riassumere, solo i @YESvalori esatti e espressi @((BOOL)expression)sono di __NSCFBooleantipo e convertiti truecon serializzazione JSON. Qualsiasi altra espressione come @(expression1 && expression2)(pari @(YES && YES)) è di __NSCFNumber (int)tipo e convertita 1in JSON.

PS Puoi semplicemente usare un valore booleano con valori di stringa

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

1

C'è un bug sottile che nessuno ha menzionato qui, che ho pensato di includere ... più di un errore logico che altro:

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

quindi il problema qui è proprio questo (YES==1)e in C il confronto non è booleano, ma basato sul valore.

perché YESè solo un #define(piuttosto che qualcosa di intrinseco al linguaggio), deve essere un valore e 1ha più senso.


Questa è essenzialmente la stessa risposta di DanJ, ​​da 2+ anni prima, con meno dettagli.
Lawrence Dol,

@LawrenceDol Non lo so, menziona che YES è solo # definito come 1 e non intrinseco alla lingua, come potrebbe essere in una lingua di livello superiore ... qualcuno potrebbe avere valore da quello ... ma buono pesca a traina, con te.
Grady Player

0

Penso che aggiungano SÌ / NO per essere più esplicativo in molti casi. Per esempio:

[button setHidden:YES];

suona meglio di

[button setHidden:TRUE];

2
Non sono d'accordo; entrambi leggono lo stesso, per me. Tuttavia, nell'interfaccia utente di un laico penso che Sì / No sia più bello.
Lawrence Dol,

16
Anch'io non sono d'accordo. Semmai, legge male a causa del non attenersi agli standard non scritti che sono stati usati per anni in altre lingue. IE è un ottimo esempio di ciò che accade quando non si aderisce a un gran numero di standard.
FreeAsInBeer,

1
Mezzo
voto negativo

-2

Per prima cosa esaminiamo cos'è vero e falso e cosa dà loro significato in primo luogo.

possiamo costruire una struttura chiamata se a then b else c nel calcolo lambda come segue:

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

In JavaScript, si presenta così:

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

affinché ifThenElse sia utile, abbiamo bisogno di una funzione "true" che scelga destra o sinistra, e lo fa ignorando l'altra opzione, o una funzione "false" che sceglie l'opzione "true" non accetta.

Possiamo definire queste funzioni come segue:

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

in JavaScript è simile al seguente:

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

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

ora possiamo fare quanto segue

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

con doThis e doThat essendo (\ a. ()) perché lambda calculus non offre alcun servizio come stampa / matematica / stringhe, tutto ciò che possiamo fare è non fare nulla e dire di averlo fatto (e successivamente imbrogliare sostituendolo con servizi in il nostro sistema che fornisce gli effetti collaterali che vogliamo)

quindi vediamo questo in azione.

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

Questo è un ambiente profondo che potrebbe essere semplificato se ci fosse permesso di usare array / mappe / argomenti / o più di un'istruzione per dividere in più funzioni, ma voglio mantenere è puro quanto posso limitarmi a funzioni di esattamente un argomento solo.

si noti che il nome Vero / Falso non ha alcun significato intrinseco, possiamo facilmente rinominarli in sì / no, sinistra / destra, destra / sinistra, zero / uno, mela / arancia. Ha un significato in quanto qualunque sia la scelta fatta, è causata solo dal tipo di scelta fatta. Quindi, se viene stampato "SINISTRA", sappiamo che il selezionatore potrebbe essere solo vero e, sulla base di questa conoscenza, possiamo guidare le nostre ulteriori decisioni.

Quindi per riassumere

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

No, SÌ / NO è un modo diverso di fare riferimento a VERO / FALSO (1/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.