Есть ли разница между ДА / НЕТ, ИСТИНА / ЛОЖЬ и истиной / ложью в target-c?


154

Простой вопрос на самом деле; есть ли разница между этими значениями (и есть ли разница между BOOL и bool)? Сотрудник упомянул, что они оценивают разные вещи в Objective-C, но когда я посмотрел на typedef в их соответствующих файлах .h, все YES / TRUE / true были определены как, 1а NO / FALSE / false - как 0. Есть ли разница?


5
С практической точки зрения разницы нет. Вероятно, вы можете делать различные трюки, чтобы продемонстрировать разницу, но вы, как правило, отклоняетесь от «неопределенного поведения».
Hot Licks

Ответы:


84

Практической разницы нет, если вы используете BOOLпеременные в качестве логических значений. C обрабатывает логические выражения на основе того, имеют ли они 0 или нет 0. Итак:

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

означает так же, как

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

вот почему вы можете оценивать любой примитивный тип или выражение как логический тест (включая, например, указатели). Обратите внимание, что вы должны сделать первое, а не второе.

Обратите внимание , что есть разница , если вы назначаете тупые значения так называемым BOOLпеременным и тест для конкретных значений, поэтому всегда использовать их как булевы и только назначить их из своих #defineзначений.

Важно отметить, что никогда не проверяйте логические значения с использованием сравнения символов - это не только рискованно, поскольку someVarможет быть назначено ненулевое значение, которое не является ДА, но, на мой взгляд, более важно, оно не может правильно выразить намерение:

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

Другими словами, используйте конструкции так, как они предназначены и задокументированы для использования, и вы избавите себя от мира боли в C.


100

Я считаю, что есть разница между boolи BOOL, проверьте эту веб-страницу для объяснения причин:
http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

Поскольку тип BOOLявляется unsigned charскорее, чем примитивным типом, переменные типа BOOLмогут содержать значения, отличные от YESи NO.

Рассмотрим этот код:

BOOL b = 42;

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

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

Выход:

б не НЕТ!
б не ДА!

Для большинства людей это ненужная проблема, но если вы действительно хотите логическое значение, лучше использовать bool. Я должен добавить: iOS SDK обычно использует BOOLв своих определениях интерфейса, так что это аргумент, который нужно придерживаться BOOL.


5
Но обратите внимание, что оригинальная реализация C не имела bool, и, следовательно, это была традиция использовать intили charв качестве логического значения, иногда с #define, чтобы скрыть разницу, а иногда нет. На самом деле, я не уверен, что даже действующие стандарты требуют boolреализации таким образом, чтобы не допустить проверки его внутренней структуры.
Hot Licks

1
Хотя, первый printfлжет. Значение bне YES, это "не ноль", что является условием проверки. Таким образом, вы должны иметь printf("b is not zero"), что не обязательно совпадает с YES. В этом случае, bоба «не ноль» и «не ДА».
Лоуренс Дол

Спасибо Лоуренс, я сделал обновление в том же духе.
Дан Джей

Действительно, я не получил второй вывод в Xcode 8.2. Где я терплю неудачу?
Игорь Кислюк

1
@HotLicks нет внутренней разницы между 0, не ноль и ложь и истина. Пока значение предназначено для логического логического значения, оно всегда будет иметь этот интерфейс для сохранения двоичной совместимости. Проблемы начинаются, когда вы используете не булевы значения, которые выглядят как булевы, например, c стандартной функцией входа в приложение библиотеки, main возвращает 0 в случае успеха, многие в конечном итоге думают об этом 0 как о булевом значении, хотя на самом деле это перечисление, определяемое приложением или определяемое пользователем значение, которое звонящие часто ожидают ненулевым при ненормальном завершении.
Дмитрий

52

Я сделал исчерпывающий тест на это. Мои результаты должны говорить сами за себя:

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

Выход:

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] не равно ИСТИНА или ДА. Поэтому проверка инициализации объекта с помощью if ([[NSObject alloc] init] == ​​TRUE) завершится неудачей. Мне никогда не было удобно, чтобы язык определял единственное «истинное» значение, когда на самом деле подойдет любое ненулевое значение.
DrFloyd5

3
@SamuelRenkert Мне никогда не было удобно, когда язык принимает небулево значение в ifили while. Как ... while("guitar gently weeps")не должно работать ...
Supuhstar

@SamuelRenkert также бэкдор Linux, который был найден в 2003 году:if (user_id = ROOT_UID)
Supuhstar

14

Вы можете прочитать ответы на этот вопрос . Таким образом, в Objective-C (из определения в 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

Основное (опасное!) Различие между trueи YESзаключается в сериализации JSON.

Например, у нас есть запрос к серверу JSON-типа, и нам нужно отправить true / false в смысле json:

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

Затем мы конвертируем его в строку JSON перед отправкой как

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

Результат

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

Из-за логики API jsonString1может возникнуть ошибка.

Так что будьте осторожны с логическими значениями в Objective-C.

В итоге, только точное @YESи приведенное значение @((BOOL)expression)имеют __NSCFBooleanтип и преобразованы в trueсериализацию JSON. Любые другие выражения типа @(expression1 && expression2)(даже @(YES && YES)) имеют __NSCFNumber (int)тип и преобразуются 1в JSON.

PS Вы можете просто использовать строковое логическое значение

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

1

Есть небольшая ошибка, о которой никто не упомянул, и я подумал, что я бы добавил ... больше логической ошибки, чем что-либо еще:

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

поэтому проблема здесь только в том, что (YES==1)в С сравнение не логическое, а основанное на значении.

потому что YESэто просто #define(а не что-то присущее языку), оно должно иметь определенную ценность и 1имеет смысл.


По сути, это тот же ответ, что и у DanJ от 2+ лет назад, с меньшей детализацией.
Лоуренс Дол

@LawrenceDol Я не знаю, там упоминается, что ДА только # определен как 1 и не присущ языку, как это может быть на языке более высокого уровня ... кто-то может получить ценность от этого ... но хорошо троллинг, с тобой.
Grady Player

0

Я думаю, что они добавляют ДА / НЕТ, чтобы быть более понятным во многих случаях. Например:

[button setHidden:YES];

звучит лучше чем

[button setHidden:TRUE];

2
Я не согласен; они оба читают то же самое, для меня. Тем не менее, в пользовательском интерфейсе для непрофессионала я думаю, что да / нет выглядит лучше.
Лоуренс Дол

16
Я тоже не согласен. Во всяком случае, он плохо читается из-за того, что не придерживается неписаных стандартов, которые годами использовались на других языках. IE является ярким примером того, что происходит, когда вы не соблюдаете множество стандартов.
FreeAsInBeer

1
Половина пониженной оценки за 2 неточных ответа и половина понижающей оценки за подпись ваших ответов
fpg1503

-2

Сначала давайте рассмотрим, что такое истина и ложь и что дает им смысл в первую очередь.

мы можем построить структуру, называемую, если a затем b, иначе c в лямбда-исчислении, следующим образом:

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

В JavaScript это выглядит так:

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

для того, чтобы ifThenElse был полезен, нам нужна функция «истина», которая выбирает правую или левую и делает это, игнорируя другую опцию, или функция «ложь», которая выбирает опцию «истина», не принимает.

Мы можем определить эти функции следующим образом:

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

в JavaScript это выглядит так:

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

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

Теперь мы можем сделать следующее

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

с doThis и doThat is (\ a. ()), потому что лямбда-исчисление не предлагает никаких услуг, таких как печать / математика / строки, все, что мы можем сделать, это ничего не делать и говорить, что мы это сделали (а затем обмануть, заменив его службами в наша система, которая обеспечивает побочные эффекты, которые мы хотим)

так что давайте посмотрим на это в действии.

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

Это глубокая среда, которую можно было бы упростить, если бы нам было разрешено использовать массивы / карты / аргументы / или более одного оператора для разделения на несколько функций, но я хочу сохранить настолько же чисто, насколько я могу ограничиться функциями только одного аргумента только.

Заметьте, что имя True / False не имеет присущего значения, мы можем легко переименовать их в yes / no, влево / вправо, right / left, zero / one, apple / orange. Это имеет значение в том, что какой бы выбор не был сделан, он вызван только тем, кто его сделал. Поэтому, если напечатано «LEFT», мы знаем, что выбор может быть только правдой, и на основе этого знания мы можем руководствоваться нашими дальнейшими решениями.

Итак, подведем итог

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

Нет, ДА / НЕТ - это другой способ обратиться к ИСТИНА / ЛОЖЬ (1/0)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.