Чи є різниця між ТАК / НІ, ПРАВДА / ЛІЖНІСТЬ та істинними / хибними в об’єкті-c?


154

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


5
З практичної точки зору різниці немає. Ви можете, мабуть, робити різні трюки, щоб продемонструвати різницю, але, як правило, ви блукаєте на територію "невизначеної поведінки".
Гарячі лизання

Відповіді:


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. Варто додати: SDK iOS зазвичай використовує BOOLвизначення інтерфейсу, так що це аргумент BOOL.


5
Але зауважте, що оригінальної реалізації C не було bool, і тому традиція використовувати булеву intабо charяк булеву, іноді з #define, щоб приховати різницю, а іноді ні. Насправді я не впевнений, що навіть сучасні стандарти потребують boolвпровадження таким чином, що перешкоджає вивченню його внутрішньої структури.
Гарячий лизає

1
Хоча, перший printfрозповідає брехню. Значення bне є YES, це "не нуль", на що перевіряється умова. Отже, ви повинні мати printf("b is not zero"), що не обов’язково те саме, що YES. У цьому випадку bє і "не нуль", і "не ТАК".
Лоуренс Дол

Дякую Лоуренсу, я зробив оновлення.
Dan J

Дійсно, я не отримав другого виводу в Xcode 8.2. Де я не вдається?
Ігор Кислюк

1
@HotLicks немає притаманної різниці між 0, не нулем, а також false та true. Поки значення має бути логічним булевим, воно завжди матиме цей інтерфейс для збереження бінарної сумісності. Проблеми починаються, коли ви використовуєте не булеві, що здаються булевими, наприклад, c стандартна функція введення додатків у бібліотеку, основна віддача 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] не дорівнює ІСТИНИ ТА ТАК. Тож тестування для ініціалізації об'єкта, якщо ([[NSObject] alloc] init] == ​​TRUE) не вдасться. Мені ніколи не було зручно з мовою, що визначає особливе "справжнє" значення, коли насправді будь-яке ненульове значення буде робити.
DrFloyd5

3
@SamuelRenkert Мені ніколи не було зручно з мовою, яка приймає не булеве значення в ifабо while. Начебто ... while("guitar gently weeps")не повинно працювати ...
Supuhstar

@SamuelRenkert також backdoor 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 sence:

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)і в C порівняння не булеве, а засноване на вартості.

оскільки YESце просто #define(а не щось властиве мові), воно повинно бути певною цінністю і 1має найбільше значення.


Це, по суті, та сама відповідь, що і у DanJ, ​​починаючи з 2+ років раніше, з меншими деталями.
Лоуренс Дол

@LawrenceDol Я не знаю, він згадує, що ТАК є лише # визначеним, щоб бути 1, а не властивим мові, як це може бути в мові вищого рівня ... тролінг, з я.
Граді

0

Я думаю, що вони додають ТАК / НІ, щоб бути більш зрозумілими у багатьох випадках. Наприклад:

[button setHidden:YES];

звучить краще, ніж

[button setHidden:TRUE];

2
Я не погоджуюсь; вони обидва читають те саме, що мені. Однак у користувальницькому інтерфейсі для непрофесійної людини я думаю, що так / ні виглядає приємніше.
Лоуренс Дол

16
Я також не згоден. Якщо що-небудь, воно читається погано через те, що не дотримуються неписаних стандартів, які роками використовуються іншими мовами. IE - це яскравий приклад того, що відбувається, коли ви не дотримуєтесь великої кількості стандартів.
FreeAsInBeer

1
Напівголова на 2 неточні відповіді та половина на нижню суму для підписання відповідей
fpg1503

-2

Спочатку давайте вивчимо, що таке істинне та хибне, і що надає їм значення в першу чергу.

ми можемо побудувати структуру, яку називають, якщо тоді 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", яка вибирає правий чи лівий, і робить це, не зважаючи на інший варіант, або функція "false", яка вибирає варіант "true", не приймає.

Ми можемо визначити ці функції так:

(\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 being (\ 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 не має притаманного значення, ми можемо легко перейменувати їх на так / ні, ліво / право, право / ліво, нуль / один, яблуко / помаранчеве. Він має значення в тому, що який би вибір не був зроблений, він обумовлений лише тим видом, який він зробив. Отже, якщо надруковано "ВЛІВО", ми знаємо, що вибір може бути лише правдою, і на основі цих знань ми можемо керувати своїми подальшими рішеннями.

Отже, підсумовуючи

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.