Cel C: BOOL vs bool

192

Widziałem „nowy typ” BOOL( YES, NO).

Czytałem, że ten typ jest prawie jak char.

Do testów zrobiłem:

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

Dobrze widzieć, że oba dzienniki wyświetlają „1” (czasami w C ++ bool jest liczbą całkowitą, a jej rozmiar wynosi 4)

Zastanawiałem się więc, czy były jakieś problemy z typem bool czy coś takiego?

Czy mogę po prostu użyć bool (wydaje się, że działa) bez utraty prędkości?

Francescu
źródło

Odpowiedzi:

198

Z definicji w 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)

Tak, możesz założyć, że BOOL jest char. Możesz użyć typu (C99) bool, ale wszystkie frameworki Apple Objective-C i większość kodu Objective-C / Cocoa używa BOOL, dzięki czemu zaoszczędzisz sobie bólu głowy, jeśli typedef kiedykolwiek się zmieni po prostu używając BOOL.

Barry Wark
źródło
17
„wszystkie frameworki Apple” - nieprawda. Spójrz na CGGeometry.h, w szczególności: CG_INLINE bool __CGPointEqualToPoint (CGPoint point1, CGPoint point2) {return point1.x == point2.x && point1.y == point2.y; }
Elliot
58
@Elliot Masz rację. Wiele frameworków C (CoreFoundation, CoreGraphics itp.) Używa C99 bool. Wszystkie frameworki Objective-C używają BOOL.
Barry Wark,
@ Cœur edytowałeś definicję przykładowego kodu BOOL, ale poniższy tekst pozostaje taki sam. Jest to trochę mylące i nieprawidłowe. Zobacz moją odpowiedź.
ciekawy
Poznałem różne zachowania, spójrz poniżej. NSInteger progressTime = 2;//any value NSInteger totalTime = 1;//any value BOOL success = (progressTime>=totalTime)// zawsze daje, NO ale gdy już otrzymam tę (progressTime>=totalTime)wartość do booltypu success, zwraca poprawny wynik. Nie rozumiem tego zachowania. Używam, Xcode 7.xa iOSwersja była 8.x. @BarryWark
Kamar Shad
34

Jak wspomniano powyżej, BOOL jest podpisanym char. bool - typ ze standardu C99 (int).

BOOL - TAK / NIE. bool - prawda / fałsz.

Zobacz przykłady:

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

I wynik jest

PRAWDZIWE b1
PRAWDZIWE b2
NIE PRAWDZIWE b2

Zauważ, że bool! = BOOL. Poniższy wynik to TYLKO PONOWNIE - PRAWDZIWE b2

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

Jeśli chcesz przekonwertować bool na BOOL, powinieneś użyć następnego kodu

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

W naszym przypadku:

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

A więc ... co teraz dostajemy? :-)

beryl
źródło
3
Możesz zamiast korzystać z potrójnego operatora !!b1. Konwersja między nimi
Richard J. Ross III
1
„NOT REAL b2” nie jest drukowany na moim symulatorze iPhone SE.
gabbler
12

W chwili pisania tego tekstu jest to najnowsza wersja 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

Oznacza to, że na 64-bitowych urządzeniach iOS i na WatchOS BOOLjest dokładnie tak samo, jak boolna wszystkich innych urządzeniach (OS X, 32-bitowy iOS), signed chara nawet nie można go zastąpić flagą kompilatora-funsigned-char

Oznacza to również, że ten przykładowy kod będzie działał inaczej na różnych platformach (sam go przetestowałem):

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

BTW nigdy nie przypisuje takich zmiennych array.countdo BOOLzmiennych, ponieważ około 0,4% możliwych wartości będzie ujemnych.

Piotr Tobolski
źródło
kompilator zgłosi błąd, jeśli użyjesz bool jako parametru bloku, który jest zdefiniowany, aby uzyskać BOOL (bloki animacji UIView, np.), kiedy kompilujesz dla iOS 32 bity (iPhone 5C ...). Używam bool C ++ wszędzie w moim kodzie i BOOL w interfejsach API zdefiniowanych w BOOL
stephane k.
8

Typ C celu, którego należy użyć, to BOOL. Nie ma nic takiego jak rodzimy typ danych boolowskich, dlatego należy upewnić się, że kod kompiluje się na wszystkich kompilatorach BOOL. (Jest to zdefiniowane w Apple-Frameworks.

Georg Schölly
źródło
2
To nie jest ściśle dokładne. BOOLjest zdefiniowany przez język Objective-C (znajduje się w jednym z objc/*.hnagłówków), a nie przez frameworki. Ponadto, podczas kompilacji z C99 (który moim zdaniem jest domyślny), istnieje natywny typ boolowski _Bool(lub booljeśli stdbool.hjest uwzględniony).
dreamlax
5

Tak, BOOL to typedef dla podpisanego znaku według objc.h.

Nie wiem jednak o bool. To jest C ++, prawda? Jeśli jest zdefiniowany jako znak podpisany, gdzie 1 to TAK / prawda, a 0 to NIE / fałsz, wyobrażam sobie, że nie ma znaczenia, którego użyjesz.

Ponieważ BOOL jest częścią Objective-C, prawdopodobnie bardziej sensowne jest użycie BOOL dla przejrzystości (inni programiści Objective-C mogą być zdziwieni, jeśli zobaczą bool w użyciu).

Jeff
źródło
6
_Bool jest zdefiniowany w C99, aw standardowym nagłówku stdbool.h zdefiniowane jest makro bool (które rozwija się do _Bool) i tutaj zdefiniowane są również wartości true / false.
Brian Mitchell
4

Kolejna różnica między bool i BOOL polega na tym, że nie konwertują one dokładnie tego samego rodzaju obiektów, gdy obserwujesz klucz-wartość lub kiedy używasz metod takich jak - [NSObject valueForKey:].

Jak wszyscy tu powiedzieli, BOOL jest char. Jako taki jest konwertowany na numer NSNumber zawierający znak. Ten obiekt jest nie do odróżnienia od numeru NSNumber utworzonego ze zwykłego znaku, takiego jak „A” lub „\ 0”. Całkowicie straciłeś informacje, że pierwotnie posiadałeś BOOL.

Jednak bool jest konwertowany na CFBoolean, który zachowuje się tak samo jak NSNumber, ale zachowuje boolowskie pochodzenie obiektu.

Nie sądzę, że jest to argument w debacie BOOL vs. bool, ale któregoś dnia może cię ugryźć.

Ogólnie rzecz biorąc, powinieneś używać BOOL, ponieważ jest to typ używany wszędzie w interfejsach API Cocoa / iOS (zaprojektowanych przed C99 i jego rodzimym typem bool).

Gwendal Roué
źródło
2

Przyjęta odpowiedź została zredagowana, a jej wyjaśnienie stało się nieco niepoprawne. Próbka kodu została odświeżona, ale poniższy tekst pozostaje taki sam. Nie można zakładać, że BOOL jest na razie char, ponieważ zależy od architektury i platformy. Dlatego jeśli uruchomisz kod na platformie 32-bitowej (na przykład iPhone 5) i wydrukujesz @encode (BOOL), zobaczysz „c”. Odpowiada typowi char . Ale jeśli uruchomisz kod na iPhonie 5s (64-bitowym), zobaczysz „B”. Odpowiada typowi bool .

ciekawy
źródło
1

Tu sprzeciwiam się konwencji. Nie lubię typedefów do typów bazowych. Myślę, że to bezużyteczne pośrednictwo, które usuwa wartość.

  1. Kiedy zobaczę typ podstawowy w twoim źródle, natychmiast go zrozumiem. Jeśli to typef, muszę to sprawdzić, żeby zobaczyć, z czym tak naprawdę mam do czynienia.
  2. Podczas przenoszenia do innego kompilatora lub dodawania innej biblioteki ich zestaw typów typef może powodować konflikty i powodować problemy, które są trudne do debugowania. Właśnie skończyłem sobie z tym radzić. W jednej bibliotece boolean został wpisany do int, aw mingw / gcc jest wpisany do char.
Sójka
źródło
4
Cóż ... można oczekiwać, że znasz standardowe typy swojego języka (pomyśl size_t), a zarówno bool(C99), jak i BOOL(ObjC) należą do tej kategorii. A jeśli twój kod zawiódł z powodu zmiany typedef, to twój kod jest winny, ponieważ najwyraźniej nie traktowałeś typedef jako nieprzejrzystej rzeczy, ale polegałeś na jego implementacji na jednej platformie. (Zdarza się, że nie ma się czego wstydzić, ale to nie jest typedef do winy.)
DevSolar
1
„Standardowe” typedefy nie wydają się bardzo standardowe (na przykład przez jakiś czas MS nie wspierało standardów posix, itp.). Jeśli nie używasz typedefs, problem ze zmianą lub odmiennością typedefs w różnych kompilatorach zostaje wyeliminowany.
Jay
1
-1, typedefs ogólnie służą dwóm ważnym celom (między innymi): zapewniają dobrą semantykę i zapewniają pewne błędy w kierowaniu. Idealnie nie powinieneś znać podstawowego typu, do którego odnosi się typedef, niestety ten system nie jest doskonały i czasami musisz wiedzieć. Chodzi mi o to: powinieneś postępować zgodnie z konwencją, ponieważ nawet przyznając, że nie jest doskonała, jest lepsza niż alternatywa.
João Portela
2
@Jay: Przepraszam, powinienem był wyjaśnić, dlaczego to „przekierowanie” jest dobre. Spróbuję podać przykład: jeśli użyjesz logiki typu typefef zamiast bezpośrednio int lub char, zezwalasz na użycie innego typu (który nadal działa) na każdej platformie bez uszkodzenia kodu [powody to się różni, ale możemy sobie wyobrazić platformę, w której znak może być źle wyrównany w pamięci, a zatem wolniejszy, więc zamiast tego można użyć wartości logicznej].
João Portela
2
@Jay: Przez „dobrą semantykę” rozumiem, że kiedy deklarujesz wartość logiczną BOOL varnamezamiast char varnameniej, bardziej oczywiste jest, że dwie poprawne wartości dla tej zmiennej to true/ YESlub false/ NO.
João Portela
1

Jak wspomniano powyżej, BOOLmoże być unsigned chartypem zależnym od architektury, podczas gdy booljest typem int. Prosty eksperyment pokaże różnicę, dlaczego BOOL i bool mogą zachowywać się inaczej:

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

Ku twojemu zdziwieniu if(objcBOOL != YES)kompilator oceni na 1, ponieważ w YESrzeczywistości jest to kod znakowy 1, aw oczach kompilatora kod znakowy 64 nie jest oczywiście równy kodowi znakowemu 1, więc instrukcja if będzie oceniać, YES/true/1a następujący wiersz będzie biegać. Ponieważ jednak booltyp zera zero zawsze zwraca wartość całkowitą 1, powyższy problem nie wpłynie na kod. Poniżej znajduje się kilka dobrych wskazówek, jeśli chcesz użyć Objective-C BOOLtypu vs ANSI C booltyp:

  • Zawsze przypisuj wartość YESlub NOi nic więcej.
  • Konwertuj BOOLtypy, używając !!operatora double not not , aby uniknąć nieoczekiwanych wyników.
  • Podczas sprawdzania YESużycia if(!myBool) instead of if(myBool != YES)znacznie czystsze jest użycie !operatora not not operator i daje oczekiwany rezultat.
ilgaar
źródło
1

Należy również pamiętać o różnicach w rzutowaniu, szczególnie podczas pracy z maskami bitowymi, ze względu na rzutowanie na podpisany znak:

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

Jeśli BOOL jest znakiem char zamiast bool, rzut 0x0100 na BOOL po prostu upuszcza ustawiony bit, a wynikowa wartość wynosi 0.

Michaf
źródło