Có sự khác biệt giữa CÓ / KHÔNG, TRUE / FALSE và đúng / sai trong mục tiêu-c không?


154

Câu hỏi đơn giản thực sự; có sự khác biệt giữa các giá trị này (và có sự khác biệt giữa BOOL và bool) không? Một đồng nghiệp đã đề cập rằng họ đánh giá những thứ khác nhau trong Objective-C, nhưng khi tôi xem các typedefs trong các tệp .h tương ứng của họ, thì CÓ / TRUE / true đều được định nghĩa là 1và NO / FALSE / false đều được định nghĩa là 0. Có thực sự có sự khác biệt?


5
Từ quan điểm thực tế không có sự khác biệt. Bạn có thể có thể thực hiện nhiều thủ thuật khác nhau để chứng minh sự khác biệt, nhưng nhìn chung bạn đang đi lạc vào lãnh thổ "hành vi không xác định".
Hot Licks

Câu trả lời:


84

Không có sự khác biệt thực tế với điều kiện bạn sử dụng BOOLcác biến là booleans. C xử lý các biểu thức boolean dựa trên việc chúng đánh giá về 0 hay không 0. Vì vậy:

if(someVar ) { ... }
if(!someVar) { ... }

có nghĩa giống như

if(someVar!=0) { ... }
if(someVar==0) { ... }

đó là lý do tại sao bạn có thể đánh giá bất kỳ loại hoặc biểu thức nguyên thủy nào dưới dạng thử nghiệm boolean (bao gồm, ví dụ, con trỏ). Lưu ý rằng bạn nên làm cái trước chứ không phải cái sau.

Lưu ý rằng có một sự khác biệt nếu bạn gán giá trị tù đến một cái gọi là BOOLbiến và kiểm tra cho các giá trị cụ thể, vì vậy luôn sử dụng chúng như các phép toán luận và chỉ gán chúng từ họ #definegiá trị.

Điều quan trọng, không bao giờ kiểm tra booleans bằng cách so sánh ký tự - nó không chỉ rủi ro vì someVarcó thể được gán một giá trị khác không mà KHÔNG CÓ, nhưng, theo tôi quan trọng hơn, nó không thể hiện chính xác ý định:

if(someVar==YES) { ... } // don't do this!
if(someVar==NO ) { ... } // don't do this either!

Nói cách khác, sử dụng các cấu trúc như chúng được dự định và ghi lại để sử dụng và bạn sẽ thoát khỏi thế giới bị tổn thương trong C.


100

Tôi tin rằng có một sự khác biệt giữa boolBOOL, hãy kiểm tra trang web này cho một lời giải thích lý do tại sao:
http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

Bởi vì BOOLunsigned charmột kiểu nguyên thủy, các biến kiểu BOOLcó thể chứa các giá trị khác YESNO.

Xem xét mã này:

BOOL b = 42;

if (b) {
    printf("b is not NO!\n");
}

if (b != YES) {
    printf("b is not YES!\n");
}

Đầu ra là:

b không phải là KHÔNG!
b không CÓ!

Đối với hầu hết mọi người, đây là một mối quan tâm không cần thiết, nhưng nếu bạn thực sự muốn một boolean thì tốt hơn là sử dụng a bool. Tôi nên thêm: SDK iOS thường sử dụng BOOLtrên các định nghĩa giao diện của nó, vì vậy đó là một đối số để gắn bó BOOL.


5
Nhưng lưu ý rằng việc triển khai C ban đầu không có bool, và do đó, đó là truyền thống sử dụng inthoặc charlàm Boolean, đôi khi với #define để che giấu sự khác biệt và đôi khi không. Trên thực tế, tôi không chắc liệu ngay cả các tiêu chuẩn hiện tại có yêu cầu boolđược thực hiện theo cách ngăn chặn việc kiểm tra cấu trúc bên trong của nó hay không.
Hot Licks

1
Mặc dù, người đầu tiên printfnói dối. Giá trị của bkhông phải YES, đó là "không phải không", đó là những gì điều kiện kiểm tra. Vì vậy, bạn nên có printf("b is not zero"), mà không nhất thiết phải giống như YES. Trong trường hợp này, bcả "không bằng không" và "không CÓ".
Lawrence Dol

Cảm ơn Lawrence, tôi đã thực hiện một bản cập nhật dọc theo những dòng đó.
Dan J

Thật vậy, tôi đã không nhận được đầu ra thứ hai trong Xcode 8.2. Tôi thất bại ở đâu?
Igor Kislyuk

1
@HotLicks không có sự khác biệt vốn có giữa 0, không phải 0 và sai và đúng. Miễn là giá trị được dự định là một boolean logic, nó sẽ luôn có giao diện này để duy trì khả năng tương thích nhị phân. Các vấn đề bắt đầu khi bạn sử dụng các booleans không giống booleans, ví dụ như hàm nhập ứng dụng thư viện chuẩn c, chính trả về 0 khi thành công, nhiều người cuối cùng nghĩ về 0 này là boolean, trong khi thực tế nó là một ứng dụng được định nghĩa hoặc liệt kê do người dùng xác định giá trị, mà callees thường mong đợi là khác không khi chấm dứt bất thường.
Dmitry

52

Tôi đã làm một bài kiểm tra toàn diện về điều này. Kết quả của tôi nên nói cho chính họ:

//These will all print "1"
NSLog(@"%d", true == true);
NSLog(@"%d", TRUE == true);
NSLog(@"%d", YES  == true);
NSLog(@"%d", true == TRUE);
NSLog(@"%d", TRUE == TRUE);
NSLog(@"%d", YES  == TRUE);
NSLog(@"%d", true == YES);
NSLog(@"%d", TRUE == YES);
NSLog(@"%d", YES  == YES);

NSLog(@"%d", false == false);
NSLog(@"%d", FALSE == false);
NSLog(@"%d", NO    == false);
NSLog(@"%d", false == FALSE);
NSLog(@"%d", FALSE == FALSE);
NSLog(@"%d", NO    == FALSE);
NSLog(@"%d", false == NO);
NSLog(@"%d", FALSE == NO);
NSLog(@"%d", NO    == NO);


//These will all print "0"
NSLog(@"%d", false == true);
NSLog(@"%d", FALSE == true);
NSLog(@"%d", NO    == true);
NSLog(@"%d", false == TRUE);
NSLog(@"%d", FALSE == TRUE);
NSLog(@"%d", NO    == TRUE);
NSLog(@"%d", false == YES);
NSLog(@"%d", FALSE == YES);
NSLog(@"%d", NO    == YES);

NSLog(@"%d", true == false);
NSLog(@"%d", TRUE == false);
NSLog(@"%d", YES  == false);
NSLog(@"%d", true == FALSE);
NSLog(@"%d", TRUE == FALSE);
NSLog(@"%d", YES  == FALSE);
NSLog(@"%d", true == NO);
NSLog(@"%d", TRUE == NO);
NSLog(@"%d", YES  == NO);

Đầu ra là:

2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.072 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.076 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.082 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.091 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.092 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.097 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.098 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.101 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0

3
[[NSObject] alloc] init] không bằng TRUE hoặc CÓ. Vì vậy, thử nghiệm khởi tạo đối tượng với if ([[NSObject] alloc] init] == ​​TRUE) sẽ thất bại. Tôi chưa bao giờ thấy thoải mái với một Ngôn ngữ xác định giá trị "đúng" duy nhất khi thực tế mọi giá trị khác không sẽ làm.
DrFloyd5

3
@SamuelRenkert Tôi chưa bao giờ thấy thoải mái với ngôn ngữ lấy giá trị phi Boolean trong một ifhoặc a while. Giống như ... while("guitar gently weeps")không nên làm việc ...
Supuhstar 20/03/2015

@SamuelRenkert cũng backdoor Linux đã được tìm thấy vào năm 2003:if (user_id = ROOT_UID)
Supuhstar

14

Bạn có thể muốn đọc câu trả lời cho câu hỏi này . Tóm lại, trong Mục tiêu-C (từ định nghĩa trong objc.h):

typedef signed char        BOOL; 
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C" 
// even if -funsigned-char is used.
#define OBJC_BOOL_DEFINED


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

11

Sự khác biệt chính (nguy hiểm!) Giữa trueYESlà trong tuần tự hóa JSON.

Ví dụ: chúng tôi có yêu cầu máy chủ kiểu JSON và cần gửi true / false trong json sence:

NSDictionary *r1 = @{@"bool" : @(true)};
NSDictionary *r2 = @{@"bool" : @(YES)};
NSDictionary *r3 = @{@"bool" : @((BOOL)true)};

Sau đó, chúng tôi chuyển đổi nó thành chuỗi JSON trước khi gửi dưới dạng

NSData *data = [NSJSONSerialization  dataWithJSONObject:requestParams options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

Kết quả là

jsonString1 // {"bool":1}
jsonString2 // {"bool":true}
jsonString3 // {"bool":true}

Do logic API jsonString1có thể dẫn đến lỗi.

Vì vậy, hãy cẩn thận với booleans trong Objective-C.

Tóm lại, chỉ chính xác @YESvà giá trị so đúc như @((BOOL)expression)là các __NSCFBooleanloại và chuyển đổi sang truevới JSON serialization. Bất kỳ biểu thức nào khác như @(expression1 && expression2)(chẵn @(YES && YES)) đều thuộc __NSCFNumber (int)loại và được chuyển đổi thành 1JSON.

PS Bạn chỉ có thể sử dụng boolean có giá trị chuỗi

@{@"bool" : @"true"}; // in JSON {"bool":true}

1

Có một lỗi tinh vi mà không ai nhắc đến ở đây, đó là tôi nghĩ rằng tôi sẽ bao gồm ... nhiều lỗi logic hơn bất cứ điều gì:

int i = 2;
if(i);        //true
if(i==YES);   // false
if((!!i)==YES); //true

Vì vậy, vấn đề ở đây chỉ là ở chỗ (YES==1)và trong C, sự so sánh không phải là một phép toán, mà là dựa trên giá trị.

bởi vì YESchỉ là một #define(chứ không phải là một cái gì đó nội tại đối với ngôn ngữ), nó phải có giá trị nhất định và 1có ý nghĩa nhất.


Đây thực chất là câu trả lời giống như của DanJ, ​​từ hơn 2 năm trước, với ít chi tiết hơn.
Lawrence Dol

@LawrenceDol Tôi không biết, nó đề cập rằng CÓ chỉ # được xác định là 1 và không phải là ngôn ngữ, giống như ngôn ngữ ở cấp độ cao hơn ... ai đó có thể nhận được giá trị từ đó ... nhưng tốt trolling, với ya.
Người chơi Grady

0

Tôi nghĩ rằng họ thêm CÓ / KHÔNG để tự giải thích nhiều hơn trong nhiều trường hợp. Ví dụ:

[button setHidden:YES];

nghe hay hơn

[button setHidden:TRUE];

2
Tôi không đồng ý; cả hai đều đọc giống nhau, với tôi. Tuy nhiên, trong một giao diện người dùng cho một giáo dân, tôi nghĩ Có / Không trông đẹp hơn.
Lawrence Dol

16
Tôi cũng không đồng ý. Nếu bất cứ điều gì, nó đọc kém do không tuân theo các tiêu chuẩn bất thành văn đã được sử dụng trong nhiều năm trong các ngôn ngữ khác. IE là một ví dụ điển hình về những gì xảy ra khi bạn không tuân thủ một số lượng lớn các tiêu chuẩn.
FreeAsInBeer

1
Một nửa downvote cho 2 câu trả lời không chính xác và một nửa downvote để ký câu trả lời của bạn
fpg1503 19/03/2015

-2

Trước tiên, hãy xem xét điều gì đúng và sai và điều gì mang lại cho chúng ý nghĩa ngay từ đầu.

chúng ta có thể xây dựng một cấu trúc được gọi là nếu a thì b khác c trong phép tính lambda như sau:

(\ifThenElse. <use if then else>)(\a. \b. \c. a b c)

Trong JavaScript, nó trông như thế này:

(function(ifThenElse) {
    // use ifThenElse
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
});

để ifThenElse trở nên hữu ích, chúng ta cần một hàm "true" chọn bên phải hoặc bên trái và thực hiện điều đó trong khi bỏ qua tùy chọn khác hoặc chức năng "false" chọn tùy chọn "true" không thực hiện.

Chúng ta có thể định nghĩa các chức năng này như sau:

(\true. <use true>)(\a. \b. a) and (\false. <use false>)(\a. \b. b)

trong JavaScript nó trông như thế này:

(function(True) {
    // use True
})(function(a) {
     return function(b) {
         return a;
     }
});

(function(False) {
    // use True
})(function(a) {
     return function(b) {
         return b;
     }
});

bây giờ chúng ta có thể làm như sau

(\true. \false. \ifThenElse. \doThis. \doThat. ifThenElse true doThis doThat)
(\a. \b. a)(\a. \b. b)(\a. \b. \c. a b c)(\a. ())(\a. ())

với do This và doThat (\ a. ()) vì tính toán lambda không cung cấp bất kỳ dịch vụ nào như in / math / chuỗi, tất cả những gì chúng ta có thể làm là không làm gì và nói rằng chúng ta đã làm điều đó (và sau đó gian lận bằng cách thay thế nó bằng các dịch vụ trong hệ thống của chúng tôi cung cấp các tác dụng phụ mà chúng tôi muốn)

vì vậy hãy xem điều này trong hành động.

(function(True) {
    return (function(False) {
        return (function(ifThenElse) {
            return (function(doThis) {
                return (function(doThat) {
                    return ifThenElse(True)(doThis)(doThat);
                });
            });
        });
    })
})(function(a) {
     return function(b) {
         return a;
     }
})(function(a) {
     return function(b) {
         return b;
     }
})(function(a) {
    return function(b) {
        return function(c) {
            return a(b)(c);
        };
    };
})(function(a) { console.log("you chose LEFT!"); })
(function(a) {console.log("you chose RIGHT");})();

Đó là một môi trường sâu có thể được đơn giản hóa nếu chúng ta được phép sử dụng mảng / ánh xạ / đối số / hoặc nhiều hơn một câu lệnh để phân chia thành nhiều hàm, nhưng tôi muốn giữ thuần túy như tôi có thể giới hạn bản thân trong các hàm của chính xác một đối số chỉ có.

Lưu ý rằng tên Đúng / Sai không có ý nghĩa cố hữu, chúng ta có thể dễ dàng đổi tên chúng thành có / không, trái / phải, phải / trái, không / một, táo / cam. Nó có ý nghĩa ở chỗ bất cứ sự lựa chọn nào được thực hiện, nó chỉ được gây ra bởi loại người chọn nó. Vì vậy, nếu "TRÁI" được in, chúng tôi biết rằng người chọn chỉ có thể đúng và dựa trên kiến ​​thức này, chúng tôi có thể hướng dẫn các quyết định tiếp theo của mình.

Vì vậy, để tóm tắt

function ChooseRight(left) {
    return function _ChooseRight_inner(right) {
        return right;
    }
}
function ChooseLeft(left) {
    return function _ChooseLeft_inner(right) {
        return left;
    }
}

var env = {
    '0': ChooseLeft,
    '1': ChooseRight,
    'false': ChooseRight,
    'true': ChooseLeft,
    'no': ChooseRight
    'yes': ChooseLeft,
    'snd': ChooseRight,
    'fst': ChooseLeft
};
var _0 = env['0'];
var _1 = env['1'];
var _true = env['true'];
var _false = env['false'];
var yes = env['yes'];
var no = env['no'];

// encodes church zero or one to boolean
function lambda_encodeBoolean(self) {
    return self(false)(true);
}
// decodes a Boolean to church zero or one
function lambda_decodeBoolean(self) {
    console.log(self, self ? env['true'] : env['false']);
    return self ? env['true'] : env['false'];
}

lambda_decodeBoolean('one' === 'two')(function() {
    console.log('one is two');
})(function() {
    console.log('one is not two');
})();

lambda_decodeBoolean('one' === 'one')(function() {
    console.log('one is one');
})(function() {
    console.log('one is not one');
})();

-7

Không, CÓ / KHÔNG là một cách khác để chỉ TRUE / FALSE (1/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.