Завдання-C: BOOL vs bool


192

Я побачив "новий тип" BOOL( YES, NO).

Я читав, що цей тип майже як чарівний.

Для тестування я зробив:

NSLog(@"Size of BOOL %d", sizeof(BOOL));
NSLog(@"Size of bool %d", sizeof(bool));

Приємно бачити, що обидва журнали відображають "1" (іноді в C ++ bool - це int, а його розмірofof 4)

Тож мені було просто цікаво, чи є проблеми з типом bool чи щось таке?

Чи можу я просто використовувати bool (який, здається, працює), не втрачаючи швидкості?

Відповіді:


199

З визначення в objc.h:

#if (TARGET_OS_IPHONE && __LP64__)  ||  TARGET_OS_WATCH
typedef bool BOOL;
#else
typedef signed char BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#endif

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

Отже, так, ви можете припустити, що BOOL - це шар. Ви можете використовувати boolтип (C99) , але всі рамки Apple Objective-C та більшість кодів Objective-C / какао використовують BOOL, так що ви збережете собі головний біль, якщо typedef колись зміниться, просто використовуючи BOOL.


17
"усі рамки Apple" - неправда. Погляньте на CGGeometry.h, зокрема: CG_INLINE bool __CGPointEqualToPoint (CGPoint point1, CGPoint point2) {return point1.x == point2.x && point1.y == point2.y; }
Елліот

58
@Elliot Ви маєте рацію. У багатьох структурах С (CoreFoundation, CoreGraphics тощо) використовується C99 bool. Всі рамки Objective-C використовують BOOL.
Баррі Ворк

@ Cœur ви відредагували визначення зразка коду BOOL, але текст нижче залишається таким же. Це трохи заплутано і неправильно. Дивіться мою відповідь.
цікаво

Знати різну поведінку, дивіться нижче. NSInteger progressTime = 2;//any value NSInteger totalTime = 1;//any value BOOL success = (progressTime>=totalTime)// Це завжди дає, NO але як тільки я отримав це (progressTime>=totalTime)значення в boolтип, successвін повертає правильний результат. Я не розумію такої поведінки. Я використовую Xcode 7.xі iOSверсія була 8.x. @BarryWark
Kamar Shad

34

Як було сказано вище, BOOL - це підписаний знак. bool - тип від стандарту C99 (int).

КУЛЬ - ТАК / НІ. bool - вірний / хибний.

Дивіться приклади:

bool b1 = 2;
if (b1) printf("REAL b1 \n");
if (b1 != true) printf("NOT REAL b1 \n");

BOOL b2 = 2;
if (b2) printf("REAL b2 \n");
if (b2 != YES) printf("NOT REAL b2 \n");

І результат є

РЕАЛЬНА b1
РЕАЛЬНА b2
НЕ РЕАЛЬНА b2

Зауважте, що bool! = BOOL. Результат нижче - лише НАДІЙСЬКО - ПРОСТО b2

b2 = b1;
if (b2) printf("ONCE AGAIN - REAL b2 \n");
if (b2 != true) printf("ONCE AGAIN - NOT REAL b2 \n");

Якщо ви хочете перетворити bool в BOOL, ви повинні використовувати наступний код

BOOL b22 = b1 ? YES : NO; //and back - bool b11 = b2 ? true : false;

Отже, у нашому випадку:

BOOL b22 = b1 ? 2 : NO;
if (b22)    printf("ONCE AGAIN MORE - REAL b22 \n");
if (b22 != YES) printf("ONCE AGAIN MORE- NOT REAL b22 \n");

І так .. що ми отримаємо зараз? :-)


3
Ви можете замість того, щоб використовувати термінальний оператор !!b1. Для перетворення між ними
Річард Дж. Росс III

1
"NOT REAL b2" не друкується на моєму тренажері iPhone SE.
габлер

12

На момент написання це остання версія objc.h:

/// Type to represent a boolean value.
#if (TARGET_OS_IPHONE && __LP64__)  ||  TARGET_OS_WATCH
#define OBJC_BOOL_IS_BOOL 1
typedef bool BOOL;
#else
#define OBJC_BOOL_IS_CHAR 1
typedef signed char BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#endif

Це означає, що на 64-розрядних пристроях iOS та на WatchOS BOOL- це абсолютно те саме, що boolі на всіх інших пристроях (OS X, 32-розрядний iOS) цеsigned char і навіть не може бути замінено прапором компілятора-funsigned-char

Це також означає, що цей приклад код працюватиме по-різному на різних платформах (тестував його сам):

int myValue = 256;
BOOL myBool = myValue;
if (myBool) {
    printf("i'm 64-bit iOS");
} else {
    printf("i'm 32-bit iOS");
}

ДО РЕЧІ не надавали речі , як array.countдо BOOLзмінної , тому що близько 0,4% від можливих значень буде негативним.


компілятор викличе помилку, якщо ви використовуєте bool як параметр блоку, визначеного для отримання BOOL (блоки анімації UIView, наприклад), коли ви компілюєте для iOS 32 біт (iPhone 5C ...). Я використовую C ++ bool скрізь у своєму коді, а BOOL - в API, визначених за допомогою BOOL
stephane k.

8

Ви повинні використовувати тип Objective-C BOOL. Немає нічого подібного до власного булевого типу даних, тому переконайтесь, що код компілюється у всіх компіляторах BOOL. (Це визначено в Apple-Frameworks.


2
Це не зовсім точно. BOOLвизначається мовою Objective-C (вона знаходиться в одному з objc/*.hзаголовків), а не рамками. Крім того, при компілюванні з C99 (що, на мою думку, є за замовчуванням), тоді є нативний булевий тип _Bool(або boolякщо stdbool.hвін включений).
dreamlax

5

Так, BOOL - це typedef для підписаного знака згідно з objc.h.

Я не знаю про bool. Це C ++ річ, правда? Якщо це визначено як підписаний знак, де 1 - ТАК / правда, а 0 - НІ / неправда, то, я думаю, це не має значення, який ви використовуєте.

Оскільки BOOL є частиною Objective-C, то, мабуть, має більше сенсу використовувати BOOL для ясності (інші розробники Objective-C можуть бути спантеличені, якщо вони побачать, що bool використовується).


6
_Bool визначено в C99, а в стандартному заголовку stdbool.h визначається макро bool (який розширюється на _Bool), а також визначається true / false.
Брайан Мітчелл

4

Ще одна відмінність між bool і BOOL полягає в тому, що вони не перетворюють точно в один і той же тип об'єктів, коли ви виконуєте спостереження за значенням ключа або значення, коли ви використовуєте такі методи, як - [NSObject valueForKey:].

Як тут всі говорили, BOOL - це чарівність. Як такий, він перетворюється на NSNumber, що містить символи. Цей об'єкт не відрізняється від NSNumber, створеного зі звичайного знаку типу "A" або "\ 0". Ви повністю втратили інформацію про те, що ви спочатку мали БУЛ.

Однак bool перетворюється на CFBoolean, який поводиться так само, як NSNumber, але який зберігає булеве походження об'єкта.

Я не думаю, що це аргумент у дискусії BOOL проти bool, але це може вас вкусити одного разу.

Взагалі кажучи, вам слід скористатися BOOL, оскільки це тип, що використовується скрізь у API-програмах какао / iOS (розроблений до C99 та його рідного типу bool).


2

Прийняту відповідь було відредаговано, і її пояснення стали трохи невірними. Зразок коду оновлено, але текст нижче залишається тим самим. Ви не можете припустити, що BOOL є символом на даний момент, оскільки це залежить від архітектури та платформи. Таким чином, якщо ви запускаєте код на 32-бітній платформі (наприклад, iPhone 5) і друкуєте @encode (BOOL), ви побачите "c". Це відповідає типу char . Але якщо запустити код на iPhone 5s (64 біт), ви побачите "B". Він відповідає типу bool .


1

Я іду проти конвенції. Мені не подобається typedef's до базових типів. Я думаю, що це марний непрямий характер, який знімає цінність.

  1. Коли я побачу базовий тип у вашому джерелі, миттєво його зрозумію. Якщо це typedef, я повинен шукати його, щоб побачити, з чим я справді маю справу.
  2. Під час перенесення іншого компілятора або додавання іншої бібліотеки їх набір typedefs може конфліктувати і спричинити проблеми, які важко налагодити. Я щойно покінчив із цим. В одній бібліотеці boolean було введено до int, а в mingw / gcc це typedef'ed to char.

4
Ну ... можна очікувати, що ви знаєте стандартний typedef своєї мови (думаю size_t), і обидва bool(C99) та BOOL(ObjC) потрапляють до цієї категорії. І якщо ваш код не вдався через зміну typedef, винний у вашому коді, оскільки ви, мабуть, не обробляли typedef як непрозору річ, але покладалися на її реалізацію на одній платформі. (Нічого не соромно, буває, але це не винний
тип, де

1
"Стандартні" typedefs не здаються дуже стандартними (наприклад, деякий час MS не підтримували стандарти posix тощо). Якщо ви не використовуєте typedefs, тоді проблема з зміною typedefs змінюється або відрізняється від різних компіляторів.
Джей

1
-1, typedefs в цілому служать двом важливим цілям (серед інших): забезпечити хорошу семантику та деяку неправильну спрямованість. В ідеалі вам не потрібно знати базовий тип, на який відноситься typedef, на жаль, ця система не є досконалою, і іноді вам це потрібно знати. Моя думка: ви повинні слідувати конвенції, бо навіть визнаєте, що її не вдосконалити краще, ніж альтернативу.
Жоао Портела

2
@Jay: Вибачте, я повинен був пояснити, чому це "неправильне спрямування" добре. Я спробую навести приклад: якщо ви використовуєте boolean typedef'd замість int або char безпосередньо, ви дозволяєте використовувати інший тип (який все ще працює) на кожній платформі, не порушуючи код [причини це різниться, але ми можемо уявити собі платформу, де знак може бути нерівним у пам'яті і, таким чином, повільніше, щоб замість нього використовувався інт для булевого].
Жоао Портела

2
@Jay: Під «хорошою семантикою» я маю на увазі, що коли ви оголошуєте свій булевий BOOL varnameзамість char varnameнього, то очевидно, що два дійсних значення для цієї змінної є true/ YESабо false/ NO.
Жоао Портела

1

Як було сказано вище, це BOOLможе бути unsigned charтип залежно від вашої архітектури, а boolтип - тип int. Простий експеримент покаже різницю, чому BOOL і bool можуть вести себе по-різному:

bool ansicBool = 64;
if(ansicBool != true) printf("This will not print\n");

printf("Any given vlaue other than 0 to ansicBool is evaluated to %i\n", ansicBool);

BOOL objcBOOL = 64;
if(objcBOOL != YES) printf("This might print depnding on your architecture\n");

printf("BOOL will keep whatever value you assign it: %i\n", objcBOOL);

if(!objcBOOL) printf("This will not print\n");

printf("! operator will zero objcBOOL %i\n", !objcBOOL);

if(!!objcBOOL) printf("!! will evaluate objcBOOL value to %i\n", !!objcBOOL);

На ваше здивування if(objcBOOL != YES), компілятор оцінить 1, оскільки YESнасправді код символу 1, а в очах компілятора, код символів 64, звичайно, не дорівнює коду символу 1, таким чином, оператор if оцінить YES/true/1і наступний рядок буде бігати. Однак оскільки boolтип " нульовий нуль" завжди присвоюється цілому значенню 1, вищезазначена проблема не вплине на ваш код. Нижче наведено кілька корисних порад, якщо ви хочете використовувати Objective-C BOOLтип проти ANSI C boolтипу:

  • Завжди призначайте значення YESабо NOзначення і більше нічого.
  • Перетворити BOOLтипи, використовуючи !!оператор " подвійний не", щоб уникнути несподіваних результатів.
  • Під час перевірки на YES використання if(!myBool) instead of if(myBool != YES)набагато чіткіше використовувати не !оператор і дає очікуваний результат.

1

Крім того, пам’ятайте про відмінності в кастингу, особливо під час роботи з бітовими масками, через кастинг до підписаних знаків:

bool a = 0x0100;
a == true;  // expression true

BOOL b = 0x0100;
b == false; // expression true on !((TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH), e.g. MacOS
b == true;  // expression true on (TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH

Якщо BOOL є підписаним символом замість bool, то від 0x0100 до BOOL просто випадає встановлений біт, і отримане значення дорівнює 0.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.