BOOL с 64-разрядной версией iOS - программирование
Подтвердить что ты не робот

BOOL с 64-разрядной версией iOS

Когда я использую BOOL для 32-битного, я получаю:

BOOL b1=8960; //b1 == NO

bool b2=8960; //b2 == true  

Но для 64-битного я получаю:

BOOL b1=8960; //b1 == YES

bool b2=8960; //b2 == true

Что изменилось в BOOL с 32-битного до 64-битного?

4b9b3361

Ответ 1

@TimBodeit прав, но это не объясняет, почему...

BOOL b1=8960; //b1 == NO

... оценивается до NO на 32-разрядной iOS и почему он оценивает YES в 64-битном iOS. Пусть начнется с того же начала.

Определение OBJC BOOL

#if (TARGET_OS_IPHONE && __LP64__)  ||  (__ARM_ARCH_7K__ >= 2)
#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 или ARMv7k (часы) он определяется как bool, а остальное как signed char.

ObjC BOOL YES и NO

Прочтите Objective-C Литералы, где вы можете найти:

Раньше тип bool был просто typedef для signed char, и YES и NO были макросы, которые расширяются до (BOOL)1 и (BOOL)0соответственно. Для поддержки выражений @YES и @NO эти макросы теперь определяется с использованием новых языковых ключевых слов в <objc/objc.h>:

#if __has_feature(objc_bool)
#define YES __objc_yes
#define NO  __objc_no
#else
#define YES ((BOOL)1)
#define NO  ((BOOL)0)
#endif

Компилятор неявно преобразует __objc_yes и __objc_no в (BOOL)1и (BOOL)0. Ключевые слова используются для устранения неоднозначности BOOL и целого числа литералы.

определение bool

bool - это макрос, определенный в stdbool.h, и он расширяется до _Bool, который является булевым типом, введенным в C99. Он может хранить два значения, 0 или 1. Ничего больше. Точнее, stdbool.h определяет четыре макроса для использования:

/* Don't define bool, true, and false in C++, except as a GNU extension. */
#ifndef __cplusplus
#define bool _Bool
#define true 1
#define false 0
#elif defined(__GNUC__) && !defined(__STRICT_ANSI__)
/* Define _Bool, bool, false, true as a GNU extension. */
#define _Bool bool
#define bool  bool
#define false false
#define true  true
#endif

#define __bool_true_false_are_defined 1

_Bool

_Bool был введен в C99 и он может содержать значения 0 или 1. Что важно:

Когда значение понижается до уровня _Bool, результат равен 0, если значение равно 0 и 1 в противном случае.

Теперь мы знаем, откуда этот беспорядок, и мы можем лучше понять, что происходит.

64-бит iOS || ARMv7k

boolbool_Bool (значения 0 или 1)

Demoting 8960 to _Bool дает 1, потому что значение не равно 0. См. Раздел (_Bool).

32-разрядная iOS

boolsigned char (значения -128 до 127).

Если вы собираетесь хранить значения int (-128 до 127) как signed char, значение не изменяется на C99 6.3.1.3. В противном случае это реализация определена (C99 цитата):

В противном случае новый тип подписан и значение не может быть представлено в этом; либо результат определяется реализацией или сигнал, определяемый реализацией.

Это означает, что clang может решить. Чтобы сделать его коротким, с настройками по умолчанию, clang обертывает его вокруг (intsigned char):

  • -129 становится 127,
  • -130 становится 126,
  • -131 становится 125,
  • ...

И в противоположном направлении:

  • 128 становится -128,
  • 129 становится -127,
  • 130 становится -126,
  • ...

Но поскольку signed char может хранить значения в диапазоне от -128 до 127, он также может хранить 0. Например 256 (int) становится 0 (signed char). И когда ваше значение 8960 обернуто вокруг...

  • 8960 становится 0,
  • 8961 становится 1,
  • 8959 становится -1,
  • ...

... он становится 0 при сохранении в signed char (8960 является кратным 256, 8960 % 256 == 0), поэтому он NO. То же самое относится к 256, 512,... кратным 256.

Я настоятельно рекомендую использовать YES, NO с bool и не полагаться на причудливые функции C, такие как int как условие в if и т.д. По этой причине Swift имеет bool, true и false, и вы не можете использовать значения int в условиях, когда ожидается bool. Просто, чтобы избежать этого беспорядка...

Ответ 2

Для 32-битного BOOL есть signed char, тогда как под 64-бит это bool.


Определение BOOL из 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