簡體   English   中英

Obj-C:比較BOOL變量真的安全嗎?

[英]Obj-C: Is it really safe to compare BOOL variables?

我以前認為在64位Obj-C運行時BOOL實際上是_Bool而且它是一個真正的類型所以這樣編寫是安全的:

BOOL a = YES; 
BOOL b = NO;
if (a != b) {...}

它一直在工作似乎很好,但今天我發現一個問題,當我使用像這樣的位字段結構:

typedef struct
{
    BOOL flag1 : 1;
} FlagsType;

FlagsType f;
f.flag1 = YES;

BOOL b = YES;

if (f.flag1 != b)
{
    // DOES GET HERE!!!
}

似乎從位字段返回的BOOL等於-1而常規BOOL為1,它們不相等!!!

請注意,我知道當一個任意整數被轉換為BOOL時的情況,因此變成一個“奇怪的”BOOL,這是不安全的比較。

但是在這種情況下,flag1字段和b都被聲明為BOOL並且從不進行轉換。 問題是什么? 這是編譯器錯誤嗎?

更大的問題是,比較BOOL是否真的安全,還是應該編寫XORing輔助函數? (這將是一件苦差事,因為布爾比較無處不在...)

我不重復使用C布爾類型解決了BOOL可能遇到的問題。 這是真的 - 特別是在這里,你可以在下面看到 - ,但大多數問題是由於錯誤存儲到布爾(C)對象造成的。 但在這種情況下, _Boolunsignedint )似乎是唯一可行的解​​決方案。 (除了帶有額外代碼的解決方案。)有一個原因:

我找不到關於Objective-C中BOOL的新行為的精確文檔,但是你發現的行為是壞的和錯誤的。 我預計最新的行為類似於_Bool 在你的情況下,這不是真的。 (感謝您找到了!)也許這是為了向后兼容。 講述全文:

在C中, int類型的對象是signed int (這與char有所不同。對於此類型,signedess是實現定義的。)

- int,signed或signed int

ISO / IEC 9899:TC3,6.7.2-2

每個逗號分隔的集合指定相同的類型,[...]

ISO / IEC 9899:TC3,6.7.2-5

但是由於歷史原因,有一個奇怪的例外:

如果int對象是位字段,則它是實現定義的,無論是signed int還是unsigned int (可能這是因為過去的某些CPU無法自動擴展部分字節整數的符號。因此,使用無符號整數更容易,因為將頂部位置零就足夠了。)

在clang上,默認值為signed int 因此根據全寬度整數int總是表示有符號整數,即使它只有一位。 一個int member : 1只能存儲0-1 (因此,使用int不是解決方案。)

每個逗號分隔的集都指定相同的類型,除了對於位字段,它是實現定義的,指定符int是指定與signed int相同的類型還是與unsigned int相同的類型。

ISO / IEC 9899:TC3,6.7.2-5

C標准表示布爾位字段是整數類型,因此參與了位字段的奇怪整數簽名規則:

位字段被解釋為由指定位數組成的有符號或無符號整數類型。

ISO / IEC 9899:TC3,6.7.2.1-9

這是您找到的行為。 因為這對於1位布爾類型沒有意義,所以C標准明確表示將1存儲到布爾位域必須在每種情況下比較等於1:

如果將值0或1存儲到_Bool類型的非零寬度位字段中,則位字段的值應等於存儲的值。

ISO / IEC 9899:TC3,6.7.2.1-9

這導致了一種奇怪的情況,即一個實現可以將寬度為1的布爾值實現為{0,-1},但必須滿足1 == -1。 大。

所以,簡短的故事: BOOL表現得像一個整數位字段(符合標准),但不參與_Bool的額外要求。

我認為這是因為遺留代碼。 (人們可以期待過去的-1。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM