วัตถุประสงค์ -C: BOOL เทียบกับบูล


192

ฉันเห็น "ประเภทใหม่" BOOL( YES, NO)

ฉันอ่านว่าประเภทนี้เกือบจะเหมือนตัวละคร

สำหรับการทดสอบฉันทำ:

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

ดีที่จะเห็นว่าทั้งสองบันทึกแสดง "1" (บางครั้งใน C ++ bool เป็น int และขนาดของมันคือ 4)

ดังนั้นฉันแค่สงสัยว่ามีปัญหาบางอย่างเกี่ยวกับประเภทบูลหรืออะไร?

ฉันสามารถใช้บูล (ซึ่งดูเหมือนว่าจะทำงาน) โดยไม่สูญเสียความเร็วได้หรือไม่

คำตอบ:


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) แต่กรอบงาน Objective-C ทั้งหมดของ Apple และรหัส Objective-C / Cocoa ส่วนใหญ่ใช้ BOOL ดังนั้นคุณจะไม่ต้องปวดหัวหาก typedef เคยเปลี่ยนโดยใช้ BOOL


17
"กรอบทั้งหมดของ Apple" - ไม่จริง ลองดูที่ CGGeometry.h โดยเฉพาะ: CG_INLINE บูล __CGPointEqualToPoint (CGPoint point1, CGPoint point2) {return point1.x == point2.x && point1.y == point2.y; }
Elliot

58
@Elliot คุณถูกต้อง หลายกรอบ C (CoreFoundation, CoreGraphics ฯลฯ ) ใช้ boolC99 BOOLทั้งหมดของการใช้กรอบวัตถุประสงค์ -C
Barry Wark

@Cur คุณได้แก้ไขคำจำกัดความของตัวอย่างรหัส 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 เป็นองค์กรที่เซ็นชื่อ บูล - พิมพ์จาก C99 มาตรฐาน (int)

บูล - ใช่ / ไม่ บูล - จริง / เท็จ

ดูตัวอย่าง:

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

และผลลัพธ์ก็คือ

REAL b1
REAL b2
ไม่จริง b2

โปรดสังเกตว่าบูลนั้น! = บูล ผลลัพธ์ด้านล่างเป็นเพียงครั้งเดียวอีกครั้ง - จริง b2

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

หากคุณต้องการแปลงบูลเป็นบูลคุณควรใช้โค้ดถัดไป

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ได้ หากต้องการแปลงระหว่างพวกเขา
Richard J. Ross III

1
'NOT REAL b2' ไม่ได้ถูกพิมพ์ลงในเครื่องจำลอง iPhone SE ของฉัน
gabbler

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

หมายความว่าบนอุปกรณ์ iOS 64 บิตและ WatchOS BOOLเป็นสิ่งเดียวกันกับboolในขณะที่อุปกรณ์อื่น ๆ ทั้งหมด (OS X, iOS 32 บิต) เป็น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");
}

BTW สิ่งที่ไม่เคยกำหนดชอบarray.countที่จะBOOLตัวแปรเพราะประมาณ 0.4% ของค่าที่เป็นไปได้จะเป็นค่าลบ


คอมไพเลอร์จะเพิ่มข้อผิดพลาดถ้าคุณใช้บูลเป็นพารามิเตอร์ของบล็อกที่กำหนดไว้เพื่อรับ BOOL (UIView แอนิเมชันบล็อกเป็นต้น) เมื่อคุณคอมไพล์สำหรับ iOS 32 บิต (iPhone 5C ... ) ฉันใช้ C ++ บูลทุกที่ในรหัสของฉันและ BOOL ใน API ที่กำหนดด้วยบูล
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

แม้ว่าฉันไม่รู้เกี่ยวกับบูล นั่นคือสิ่ง C ++ ใช่มั้ย ถ้ามันถูกกำหนดให้เป็น char ที่เซ็นชื่อโดยที่ 1 คือ YES / true และ 0 คือ NO / false ฉันก็นึกว่ามันไม่สำคัญว่าคุณจะใช้อันไหน

เนื่องจาก BOOL เป็นส่วนหนึ่งของ Objective-C แต่ก็อาจเหมาะสมกว่าที่จะใช้ BOOL เพื่อความชัดเจน (นักพัฒนา Objective-C อื่นอาจงงหากพวกเขาเห็นบูลที่ใช้งานอยู่


6
_Bool ถูกกำหนดใน C99 และในส่วนหัวมาตรฐาน stdbool.h นั้นมาโครบูลจะถูกกำหนด (ซึ่งขยายเป็น _Bool) และจริง / เท็จจะถูกกำหนดที่นี่เช่นกัน
Brian Mitchell

4

ความแตกต่างอีกอย่างระหว่างบูลและบูลคือมันไม่ได้แปลงไปเป็นวัตถุชนิดเดียวกันเมื่อคุณทำการสังเกตค่าคีย์หรือเมื่อคุณใช้วิธีการเช่น - [NSObject valueForKey:]

อย่างที่ทุกคนพูดไว้ที่นี่ ดังนั้นมันจึงถูกแปลงเป็น NSNumber ที่ถือถ่าน วัตถุนี้แยกไม่ออกจาก NSNumber ที่สร้างจากอักขระปกติเช่น 'A' หรือ '\ 0' คุณได้สูญเสียข้อมูลทั้งหมดที่คุณมีใน BOOL

อย่างไรก็ตามบูลจะถูกแปลงเป็น CFBoolean ซึ่งทำงานเหมือนกับ NSNumber แต่ยังคงต้นกำเนิดบูลีนของวัตถุ

ฉันไม่คิดว่านี่เป็นข้อโต้แย้งในการถกเถียงเรื่องบูลกับบูล แต่เรื่องนี้อาจจะกัดคุณในวันหนึ่ง

โดยทั่วไปแล้วคุณควรไปกับ BOOL เนื่องจากเป็นประเภทที่ใช้ทุกที่ใน Cocoa / iOS API (ออกแบบมาก่อน C99 และประเภทบูลดั้งเดิม)


2

แก้ไขคำตอบที่ยอมรับแล้วและคำอธิบายนั้นไม่ถูกต้อง ตัวอย่างโค้ดได้รับการรีเฟรช แต่ข้อความด้านล่างยังคงเหมือนเดิม คุณไม่สามารถสันนิษฐานได้ว่า BOOL เป็นตัวละครในตอนนี้เพราะมันขึ้นอยู่กับสถาปัตยกรรมและแพลตฟอร์ม ดังนั้นหากคุณรันโค้ดที่แพลตฟอร์ม 32 บิต (เช่น iPhone 5) และพิมพ์ @ encode (BOOL) คุณจะเห็น "c" มันสอดคล้องกับประเภทถ่าน แต่ถ้าคุณเรียกใช้รหัสที่ iPhone 5s (64 บิต) คุณจะเห็น "B" มันสอดคล้องกับประเภทบู


1

ฉันต่อต้านการประชุมที่นี่ ฉันไม่ชอบประเภทของประเภทฐาน ฉันคิดว่ามันเป็นทางอ้อมที่ไร้ประโยชน์ที่กำจัดค่า

  1. เมื่อฉันเห็นประเภทพื้นฐานในแหล่งที่มาของคุณฉันจะเข้าใจได้ทันที หากเป็นประเภทที่ฉันต้องค้นหามันเพื่อดูว่าฉันกำลังทำอะไรอยู่
  2. เมื่อย้ายไปยังคอมไพเลอร์อื่นหรือเพิ่มไลบรารีอื่นชุดของ typedefs อาจขัดแย้งและทำให้เกิดปัญหาที่ยากต่อการตรวจแก้จุดบกพร่อง ฉันเพิ่งจัดการกับเรื่องนี้ในความเป็นจริง ในบูลีนหนึ่งไลบรารีนั้นถูกพิมพ์เป็น int และใน mingw / gcc มันจะถูกพิมพ์เป็น char

4
ดี ... คุณสามารถรู้ได้ว่าภาษาของคุณพิมพ์ดีดมาตรฐาน (คิดsize_t) และทั้งbool(C99) และBOOL(ObjC) ตกอยู่ในหมวดหมู่นั้น และถ้ารหัสของคุณล้มเหลวเนื่องจากมีการเปลี่ยนแปลง typedef มันเป็นรหัสของคุณที่จะตำหนิเพราะเห็นได้ชัดว่าคุณไม่ได้จัดการ typedef เป็นสิ่งที่ทึบแสง แต่อาศัยการใช้งานบนแพลตฟอร์มเดียว (อะไรที่น่าละอายของมันเกิดขึ้น แต่ก็ไม่ได้ typedef ที่จะตำหนิ.)
DevSolar

1
typedef "มาตรฐาน" ดูเหมือนจะไม่ได้มาตรฐานมาก (เช่นในขณะที่ MS ไม่สนับสนุนมาตรฐาน posix ฯลฯ ) หากคุณไม่ได้ใช้ typedef แล้วปัญหาเกี่ยวกับการเปลี่ยน typedefs หรือแตกต่างกันในคอมไพเลอร์ที่แตกต่างกันจะถูกกำจัด
Jay

1
-1, typedefs โดยทั่วไปให้บริการสองวัตถุประสงค์ที่สำคัญ (ในหมู่อื่น ๆ ): ให้ความหมายที่ดีและให้คำแนะนำที่ผิดบางอย่าง เป็นการดีที่คุณไม่จำเป็นต้องรู้ประเภทฐานที่ typedef แต่น่าเสียดายที่ระบบนี้ไม่สมบูรณ์และบางครั้งคุณต้องรู้ ประเด็นของฉันคือคุณควรปฏิบัติตามอนุสัญญาเพราะแม้ยอมรับว่ามันไม่สมบูรณ์แบบดีกว่าทางเลือกอื่น
João Portela

2
@Jay: ขออภัยฉันควรจะอธิบายว่าทำไมการ "ทำผิด" นี้ดี ฉันจะพยายามให้ตัวอย่าง: ถ้าคุณใช้บูลีน typedef'd แทนที่จะใช้ int หรือตัวอักษรโดยตรงคุณจะอนุญาตให้ใช้ประเภทอื่น (ยังใช้งานได้) ในแต่ละแพลตฟอร์มโดยไม่ทำลายรหัสของคุณ สิ่งนี้แตกต่างกันไป แต่เราสามารถจินตนาการแพลตฟอร์มที่มีอักขระที่ไม่ตรงแนวในหน่วยความจำและทำให้ช้าลงดังนั้นจึงอาจใช้ int สำหรับบูลีนแทน]
João Portela

2
@Jay: โดย "ความหมายดี" ผมหมายถึงว่าเมื่อคุณประกาศบูลของคุณBOOL varnameแทนchar varnameก็เป็นที่ชัดเจนมากขึ้นว่าทั้งสองค่าที่ถูกต้องสำหรับตัวแปรที่มีtrue/ YESหรือ/false NO
João Portela

1

ดังกล่าวข้างต้นBOOLอาจจะเป็นunsigned charประเภทขึ้นอยู่กับสถาปัตยกรรมของคุณในขณะที่เป็นประเภทbool intการทดสอบอย่างง่ายจะแสดงความแตกต่างว่าทำไมบูลและบูลสามารถทำงานแตกต่างกันได้

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ประเภท vs ANSI C boolประเภท:

  • กำหนดค่าYESหรือNOค่าเสมอและไม่มีอะไรอื่น
  • แปลงBOOLชนิดโดยใช้!!ตัวดำเนินการที่ไม่ใช่คู่เพื่อหลีกเลี่ยงผลลัพธ์ที่ไม่คาดคิด
  • เมื่อตรวจสอบการYESใช้if(!myBool) instead of if(myBool != YES)มันสะอาดกว่าการใช้ตัว!ดำเนินการที่ไม่ใช่และให้ผลลัพธ์ที่คาดหวัง

1

นอกจากนี้โปรดระวังความแตกต่างในการคัดเลือกนักแสดงโดยเฉพาะเมื่อทำงานกับ bitmasks เนื่องจากการคัดเลือกนักแสดงที่ลงนาม:

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 เป็นอักขระที่ลงนามแทนบูลการโยนของ 0x0100 ไปยัง BOOL จะลดลงเพียงบิตที่ตั้งไว้และค่าที่ได้คือ 0

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.