Y a-t-il une différence entre OUI / NON, VRAI / FAUX et Vrai / Faux dans objective-c?

154

Question simple vraiment; y a-t-il une différence entre ces valeurs (et y a-t-il une différence entre BOOL et bool)? Un collègue a mentionné qu'ils évaluaient à différentes choses dans Objective-C, mais quand j'ai regardé les typedefs dans leurs fichiers .h respectifs, YES / TRUE / true étaient tous définis comme 1et NO / FALSE / false étaient tous définis comme 0. Y a-t-il vraiment une différence?

Kevlar
la source
5
D'un point de vue pratique, il n'y a pas de différence. Vous pouvez probablement faire diverses astuces pour démontrer une différence, mais vous vous égareriez généralement en territoire de "comportement indéfini".
Hot Licks

Réponses:

84

Il n'y a aucune différence pratique à condition d'utiliser des BOOLvariables comme booléens. C traite les expressions booléennes selon qu'elles évaluent à 0 ou non à 0. Donc:

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

signifie la même chose que

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

c'est pourquoi vous pouvez évaluer n'importe quel type ou expression primitive comme un test booléen (y compris, par exemple, des pointeurs). Notez que vous devriez faire le premier, pas le second.

Notez qu'il y a une différence si vous attribuez des valeurs à un obtus que l' on appelle BOOLvariable et test pour des valeurs spécifiques, donc toujours les utiliser comme booléens et seulement les affecter de leurs #definevaleurs.

Surtout, ne testez jamais les booléens en utilisant une comparaison de caractères - ce n'est pas seulement risqué car on someVarpourrait attribuer une valeur non nulle qui n'est pas OUI, mais, à mon avis plus important encore, cela ne parvient pas à exprimer correctement l'intention:

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

En d'autres termes, utilisez des constructions telles qu'elles sont prévues et documentées pour être utilisées et vous vous épargnerez un monde de blessures en C.

Lawrence Dol
la source
100

Je crois qu'il y a une différence entre boolet BOOL, consultez cette page Web pour une explication de pourquoi:
http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

Comme il BOOLs'agit d'un type unsigned charplutôt que primitif, les variables de type BOOLpeuvent contenir des valeurs autres que YESet NO.

Considérez ce code:

BOOL b = 42;

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

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

La sortie est:

b n'est pas NON!
b n'est pas OUI!

Pour la plupart des gens, c'est une préoccupation inutile, mais si vous voulez vraiment un booléen, il est préférable d'utiliser un bool. Je devrais ajouter: le SDK iOS utilise généralement BOOLsur ses définitions d'interface, c'est donc un argument avec lequel s'en tenir BOOL.

Dan J
la source
5
Mais notez que l'implémentation C d'origine n'avait pas bool, et par conséquent, il était de tradition d'utiliser un intou charcomme un booléen, parfois avec un #define pour masquer la différence et parfois pas. En fait, je ne sais pas si même les normes actuelles booldoivent être mises en œuvre d'une manière qui empêche d'examiner sa structure interne.
Hot Licks
1
Bien que, le premier printfraconte des mensonges. La valeur de bn'est pas YES, ce n'est pas zéro, ce que teste la condition. Donc, vous devriez avoir printf("b is not zero"), ce qui n'est pas nécessairement le même que YES. Dans ce cas, best à la fois "différent de zéro" et "pas OUI".
Lawrence Dol
Merci Lawrence, j'ai fait une mise à jour dans ce sens.
Dan J
En effet, je n'ai pas obtenu la deuxième sortie dans Xcode 8.2. Où j'échoue?
Igor Kislyuk
1
@HotLicks il n'y a pas de différence inhérente entre 0, pas zéro et faux et vrai. Tant que la valeur est destinée à être un booléen logique, elle aura toujours cette interface afin de préserver la compatibilité binaire. Les problèmes commencent lorsque vous utilisez des non booléens qui ressemblent à des booléens, par exemple la fonction d'entrée d'application de la bibliothèque standard c, main renvoie 0 en cas de succès, beaucoup finissent par considérer ce 0 comme un booléen, alors qu'en fait c'est une énumération définie par l'application ou définie par l'utilisateur valeur, que les appelées s'attendent souvent à être différente de zéro en cas de terminaison anormale.
Dmitry
52

J'ai fait un test exhaustif à ce sujet. Mes résultats devraient parler d'eux-mêmes:

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

La sortie est:

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
Supuhstar
la source
3
[[NSObject] alloc] init] n'est pas égal à TRUE ou YES. Donc, le test de l'initialisation d'objet avec if ([[NSObject] alloc] init] == ​​TRUE) échouera. Je n'ai jamais été à l'aise avec un langage définissant une valeur «vraie» singulière alors qu'en fait une valeur non nulle fera l'affaire.
DrFloyd5
3
@SamuelRenkert Je n'ai jamais été à l'aise avec un langage prenant une valeur non booléenne dans un ifou un while. Comme ... while("guitar gently weeps")ne devrait pas fonctionner ...
Supuhstar
@SamuelRenkert également la porte dérobée Linux qui a été trouvée en 2003:if (user_id = ROOT_UID)
Supuhstar
14

Vous voudrez peut-être lire les réponses à cette question . En résumé, en Objective-C (d'après la définition en 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
Barry Wark
la source
11

La principale différence (dangereuse!) Entre trueet YESréside dans la sérialisation JSON.

Par exemple, nous avons une requête de serveur de type JSON et devons envoyer true / false dans json sens:

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

Ensuite, nous le convertissons en chaîne JSON avant de l'envoyer en tant que

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

Le résultat est

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

En raison de la logique de l'API, jsonString1une erreur peut survenir.

Soyez donc prudent avec les booléens en Objective-C.

Pour résumer, seules les @YESvaleurs exactes et castées @((BOOL)expression)sont de __NSCFBooleantype et converties en truesérialisation JSON. Toutes les autres expressions comme @(expression1 && expression2)(paire @(YES && YES)) sont de __NSCFNumber (int)type et converties 1en JSON.

PS Vous pouvez simplement utiliser un booléen à valeur chaîne

@{@"bool" : @"true"}; // in JSON {"bool":true}
malex
la source
1

Il y a un bug subtil que personne n'a mentionné ici, que je pensais inclure ... plus une erreur logique qu'autre chose:

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

donc le problème ici est juste cela (YES==1)et en C la comparaison n'est pas booléenne, mais basée sur la valeur.

parce que YESc'est juste un #define(plutôt que quelque chose d'intrinsèque à la langue), il doit avoir une certaine valeur, et 1cela a le plus de sens.

Joueur de Grady
la source
C'est essentiellement la même réponse que celle de DanJ, ​​datant de plus de 2 ans, avec moins de détails.
Lawrence Dol
@LawrenceDol Je ne sais pas, il mentionne que OUI est seulement # défini comme étant 1 et non intrinsèque au langage, comme cela pourrait être dans un langage de niveau supérieur ... quelqu'un pourrait peut-être en tirer de la valeur ... mais bon trolling, avec toi.
Grady Player
0

Je pense qu'ils ajoutent OUI / NON pour être plus explicites dans de nombreux cas. Par exemple:

[button setHidden:YES];

sonne mieux que

[button setHidden:TRUE];
Marco
la source
2
Je ne suis pas d'accord; ils lisent tous les deux la même chose, pour moi. Cependant, dans une interface utilisateur pour un profane, je pense que oui / non est plus joli.
Lawrence Dol
16
Je suis également en désaccord. Si quoi que ce soit, il lit mal en raison de ne pas coller aux normes non écrites qui ont été utilisées pendant des années dans d'autres langues. IE est un excellent exemple de ce qui se passe lorsque vous ne respectez pas un grand nombre de normes.
FreeAsInBeer
1
Moitié contre pour 2 réponses imprécises et moitié contre pour avoir signé vos réponses
fpg1503
-2

Examinons d'abord ce qu'est le vrai et le faux et ce qui leur donne un sens en premier lieu.

nous pouvons construire une structure appelée if a then b else c dans le calcul lambda comme suit:

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

En JavaScript, cela ressemble à ceci:

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

pour que ifThenElse soit utile, nous avons besoin d'une fonction "true" qui choisit soit la droite soit la gauche, et le fait en ignorant l'autre option, ou une fonction "false" qui choisit l'option "true" ne prend pas.

Nous pouvons définir ces fonctions comme suit:

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

en JavaScript, cela ressemble à ceci:

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

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

maintenant nous pouvons faire ce qui suit

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

avec doThis et doThat étant (\ a. ()) parce que le calcul lambda n'offre aucun service tel que l'impression / maths / chaînes, tout ce que nous pouvons faire est de ne rien faire et dire que nous l'avons fait (et plus tard tricher en le remplaçant par des services dans notre système qui fournit les effets secondaires que nous voulons)

alors voyons cela en action.

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

C'est un environnement profond qui pourrait être simplifié si nous étions autorisés à utiliser des tableaux / cartes / arguments / ou plus d'une instruction pour diviser en plusieurs fonctions, mais je veux garder c'est aussi pur que je peux me limiter aux fonctions d'exactement un argument seulement.

notez que le nom True / False n'a aucune signification inhérente, nous pouvons facilement les renommer en oui / non, gauche / droite, droite / gauche, zéro / un, pomme / orange. Cela a une signification en ce que quel que soit le choix qui est fait, il n'est causé que par le type de choix qui l'a fait. Donc, si "LEFT" est imprimé, nous savons que le sélecteur ne peut être que vrai, et sur la base de cette connaissance, nous pouvons guider nos décisions ultérieures.

Donc pour résumer

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');
})();
Dmitry
la source
-7

Non, OUI / NON est une manière différente de se référer à TRUE / FALSE (1/0)

Marco
la source