Mục tiêu-C: BOOL vs bool


192

Tôi thấy "loại mới" BOOL( YES, NO).

Tôi đọc rằng loại này gần giống như một char.

Để thử nghiệm tôi đã làm:

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

Thật tốt khi thấy cả hai bản ghi hiển thị "1" (đôi khi trong C ++ bool là một int và sizeof của nó là 4)

Vì vậy, tôi chỉ tự hỏi nếu có một số vấn đề với loại bool hoặc một cái gì đó?

Tôi chỉ có thể sử dụng bool (có vẻ như hoạt động) mà không mất tốc độ?

Câu trả lời:


198

Từ định nghĩa trong 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)

Vì vậy, vâng, bạn có thể cho rằng BOOL là một char. Bạn có thể sử dụng loại (C99) bool, nhưng tất cả các khung Objective-C của Apple và hầu hết mã Objective-C / Ca cao đều sử dụng BOOL, vì vậy bạn sẽ tự cứu mình nếu typedef thay đổi chỉ bằng cách sử dụng BOOL.


17
"Tất cả các khuôn khổ của Apple" - không đúng sự thật. Hãy xem CGGeometry.h, cụ thể: CG_INLINE bool __CGPointEqualToPoint (CGPoint point1, CGPoint point2) {return point1.x == point2.x && point1.y == point2.y; }
Elliot

58
@Elliot Bạn đúng rồi. Nhiều khung C (CoreFoundation, CoreGraphics, v.v.) sử dụng C99 bool. Tất cả các khung Objective-C đều sử dụng BOOL.
Barry Wark

@ Cur bạn đã chỉnh sửa định nghĩa của mẫu mã BOOL, nhưng văn bản dưới đây vẫn giữ nguyên. Đó là một chút khó hiểu và không chính xác. Xem câu trả lời của tôi.
tò mò

Phải biết hành vi khác nhau hãy xem bên dưới. NSInteger progressTime = 2;//any value NSInteger totalTime = 1;//any value BOOL success = (progressTime>=totalTime)// nó luôn luôn cho NO Nhưng một khi tôi nhận được (progressTime>=totalTime)giá trị đó thành boolkiểu successthì nó trả về kết quả đúng. Tôi không hiểu hành vi này. Tôi đang sử dụng Xcode 7.xiOSphiên bản là 8.x. @BarryWark
Kamar Shad

34

Như đã đề cập ở trên, BOOL là một char đã ký. bool - gõ từ tiêu chuẩn C99 (int).

BOOL - CÓ / KHÔNG. bool - đúng / sai.

Xem ví dụ:

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

Và kết quả là

REAL b1
REAL b2
KHÔNG THỰC SỰ b2

Lưu ý rằng bool! = BOOL. Kết quả dưới đây chỉ là MỘT LẦN NỮA - THỰC SỰ b2

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

Nếu bạn muốn chuyển đổi bool sang BOOL, bạn nên sử dụng mã tiếp theo

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

Vì vậy, trong trường hợp của chúng tôi:

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

Và vì vậy .. những gì chúng ta nhận được bây giờ? :-)


3
Bạn có thể, thay vì sử dụng toán tử ternary sử dụng !!b1. Để chuyển đổi giữa họ
Richard J. Ross III

1
'KHÔNG THỰC SỰ b2' không được in trên trình giả lập iPhone SE của tôi.
gabbler

12

Tại thời điểm viết bài này là phiên bản mới nhất của 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

Điều đó có nghĩa là trên các thiết bị iOS 64 bit và trên WatchOS BOOLhoàn toàn giống với boolcác thiết bị khác (OS X, iOS 32 bit) signed charvà thậm chí không thể bị ghi đè bởi cờ trình biên dịch-funsigned-char

Điều đó cũng có nghĩa là mã ví dụ này sẽ chạy khác nhau trên các nền tảng khác nhau (bản thân nó đã thử nghiệm):

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

BTW thứ không bao giờ assign thích array.countđể BOOLbiến vì khoảng 0,4% của giá trị có thể sẽ là tiêu cực.


trình biên dịch sẽ phát sinh lỗi nếu bạn sử dụng bool làm tham số của một khối được xác định để lấy BOOL (khối hoạt hình UIView, ví dụ), khi bạn biên dịch cho iOS 32 bit (iPhone 5C ...). Tôi sử dụng bool C ++ ở mọi nơi trong mã của mình và BOOL trong các API được xác định bằng BOOL
stephane k.

8

Loại Objective-C bạn nên sử dụng là BOOL. Không có gì giống như kiểu dữ liệu boolean riêng, do đó để chắc chắn rằng mã biên dịch trên tất cả các trình biên dịch sử dụng BOOL. (Nó được định nghĩa trong Apple-Frameworks.


2
Điều này không hoàn toàn chính xác. BOOLđược định nghĩa bởi ngôn ngữ Objective-C (nó nằm trong một trong các objc/*.htiêu đề), không phải bởi các khung. Ngoài ra, khi biên dịch với C99 (mà tôi nghĩ là mặc định), thì có một loại Boolean riêng, _Bool(hoặc boolnếu stdbool.hđược bao gồm).
dreamlax

5

Yup, BOOL là một typedef cho một char đã ký theo objc.h.

Tôi không biết về bool, mặc dù. Đó là một thứ C ++, phải không? Nếu nó được định nghĩa là char đã ký trong đó 1 là CÓ / đúng và 0 là KHÔNG / sai, thì tôi tưởng tượng bạn không sử dụng loại nào.

Vì BOOL là một phần của Objective-C, tuy nhiên, có lẽ sẽ hợp lý hơn khi sử dụng BOOL cho rõ ràng (các nhà phát triển Objective-C khác có thể bối rối nếu họ thấy sử dụng bool).


6
_Bool được định nghĩa trong C99 và trong tiêu đề tiêu chuẩn stdbool.h, bool macro được xác định (mở rộng thành _Bool) và true / false cũng được định nghĩa ở đây.
Brian Mitchell

4

Một điểm khác biệt giữa bool và BOOL là chúng không chuyển đổi chính xác thành cùng loại đối tượng, khi bạn thực hiện quan sát khóa-giá trị hoặc khi bạn sử dụng các phương thức như - [NSObject valueForKey:].

Như mọi người đã nói ở đây, BOOL là char. Như vậy, nó được chuyển đổi thành NSNumber cầm char. Đối tượng này không thể phân biệt với NSNumber được tạo từ một char thông thường như 'A' hoặc '\ 0'. Bạn đã hoàn toàn mất thông tin rằng ban đầu bạn có BOOL.

Tuy nhiên, bool được chuyển đổi thành CFBoolean, hoạt động giống như NSNumber, nhưng vẫn giữ nguyên nguồn gốc boolean của đối tượng.

Tôi không nghĩ rằng đây là một cuộc tranh luận trong một cuộc tranh luận BOOL so với bool, nhưng điều này có thể cắn bạn một ngày nào đó.

Nói chung, bạn nên đi với BOOL, vì đây là loại được sử dụng ở mọi nơi trong API Cacao / iOS (được thiết kế trước C99 và loại bool gốc của nó).


2

Câu trả lời được chấp nhận đã được chỉnh sửa và lời giải thích của nó trở nên hơi sai. Mẫu mã đã được làm mới, nhưng văn bản dưới đây vẫn giữ nguyên. Bạn không thể cho rằng BOOL là một char ngay bây giờ vì nó phụ thuộc vào kiến ​​trúc và nền tảng. Do đó, nếu bạn chạy mã của mình ở nền tảng 32 bit (ví dụ iPhone 5) và in @encode (BOOL), bạn sẽ thấy "c". Nó tương ứng với một loại char . Nhưng nếu bạn chạy mã của bạn ở iPhone 5s (64 bit), bạn sẽ thấy "B". Nó tương ứng với một loại bool .


1

Tôi đi ngược lại quy ước ở đây. Tôi không thích typedef là loại cơ sở. Tôi nghĩ rằng đó là một sự vô cảm vô dụng mà loại bỏ giá trị.

  1. Khi tôi thấy loại cơ sở trong nguồn của bạn, tôi sẽ hiểu ngay lập tức. Nếu đó là một typedef tôi phải tìm kiếm nó để xem những gì tôi thực sự giải quyết.
  2. Khi chuyển sang trình biên dịch khác hoặc thêm thư viện khác, tập hợp typedefs của chúng có thể xung đột và gây ra các vấn đề khó gỡ lỗi. Tôi vừa mới thực hiện xong việc này. Trong một thư viện, boolean đã được nhập vào int và trong mingw / gcc, nó được nhập vào một char.

4
Chà ... bạn có thể được dự kiến ​​sẽ biết ngôn ngữ tiêu chuẩn của ngôn ngữ của bạn (nghĩ size_t) và cả bool(C99) và BOOL(ObjC) đều thuộc loại đó. Và nếu mã của bạn thất bại vì thay đổi typedef, thì mã của bạn sẽ bị đổ lỗi vì rõ ràng bạn không xử lý typedef như một điều mờ đục mà chỉ dựa vào việc triển khai trên một nền tảng. (Không có gì phải xấu hổ, điều đó xảy ra, nhưng đó không phải là lỗi đáng trách.)
DevSolar

1
Typedefs "tiêu chuẩn" dường như không chuẩn lắm (ví dụ trong một thời gian MS không hỗ trợ các tiêu chuẩn posix, v.v.). Nếu bạn không sử dụng typedefs thì vấn đề với typedefs thay đổi hoặc khác biệt trên các trình biên dịch khác nhau sẽ được loại bỏ.
Jay

1
-1, typedefs nói chung phục vụ hai mục đích quan trọng (trong số những mục đích khác): cung cấp ngữ nghĩa tốt và cung cấp một số định hướng sai. Lý tưởng nhất là bạn không cần phải biết loại cơ sở mà typedef đề cập đến, thật không may hệ thống này không hoàn hảo và đôi khi bạn phải biết. Quan điểm của tôi là: bạn nên tuân theo quy ước bởi vì thậm chí thừa nhận rằng nó không hoàn hảo hơn so với giải pháp thay thế.
João Portela

2
@Jay: Xin lỗi, tôi nên giải thích lý do tại sao "định hướng sai" này là tốt. Tôi sẽ cố gắng đưa ra một ví dụ: nếu bạn sử dụng boolean typedef'd thay vì sử dụng int hoặc char trực tiếp, bạn sẽ cho phép một loại khác (vẫn hoạt động) được sử dụng trên mỗi nền tảng mà không phá vỡ mã của bạn điều này khác nhau nhưng chúng ta có thể tưởng tượng một nền tảng trong đó char có thể bị điều chỉnh sai trong bộ nhớ và do đó chậm hơn để một int có thể được sử dụng cho boolean thay thế].
João Portela

2
@Jay: Bởi "ngữ nghĩa tốt" Ý tôi là khi bạn khai báo boolean của bạn BOOL varnamethay vì char varnamerõ ràng hơn là hai giá trị hợp lệ cho biến đó là true/ YEShoặc false/ NO.
João Portela

1

Như đã đề cập ở trên BOOLcó thể là một unsigned charloại tùy thuộc vào kiến ​​trúc của bạn, trong khi boollà loại int. Một thử nghiệm đơn giản sẽ cho thấy sự khác biệt tại sao BOOL và bool có thể cư xử khác nhau:

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

Bạn ngạc nhiên if(objcBOOL != YES)sẽ đánh giá thành 1 bởi trình biên dịch, vì YESthực tế là mã ký tự 1 và trong mắt trình biên dịch, mã ký tự 64 tất nhiên không bằng mã ký tự 1 do đó câu lệnh if sẽ đánh giá YES/true/1và dòng sau sẽ chạy. Tuy nhiên do loại không có boolgiá trị luôn luôn ước tính giá trị nguyên là 1, nên vấn đề trên sẽ không ảnh hưởng đến mã của bạn. Dưới đây là một số mẹo hay nếu bạn muốn sử dụng Objective-C BOOLloại so với ANSI C boolloại:

  • Luôn luôn chỉ định YEShoặc NOgiá trị và không có gì khác.
  • Chuyển đổi BOOLcác loại bằng cách sử dụng gấp đôi không phải !!toán tử để tránh kết quả không mong muốn.
  • Khi kiểm tra để YESsử dụng, if(!myBool) instead of if(myBool != YES)nó sẽ sạch hơn nhiều khi sử dụng !toán tử không và cho kết quả như mong đợi.

1

Ngoài ra, hãy lưu ý đến sự khác biệt trong quá trình truyền, đặc biệt là khi làm việc với bitmasks, do việc truyền sang ký char:

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

Nếu BOOL là một char đã ký thay vì bool, thì việc chuyển 0x0100 sang BOOL chỉ đơn giản là giảm bit đã đặt và giá trị kết quả là 0.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.