簡體   English   中英

為什么要用!! 將 int 轉換為 bool 時?

[英]Why use !! when converting int to bool?

以這種方式將整數轉換為布爾值的原因是什么?

bool booleanValue = !!integerValue;

而不僅僅是

bool booleanValue = integerValue;

我所知道的是,在 VC++7 中,后者會導致C4800 警告,而前者不會。 兩者之間還有其他區別嗎?

“!!”的問題習語是它很簡潔,很難看,很容易被誤認為是打字錯誤,很容易去掉一個“!”,等等。 我把它歸入“看看我們可以用 C/C++ 多可愛”的類別。

只需寫bool isNonZero = (integerValue != 0); ... 清楚。

從歷史上看, !! idiom 用於確保您的 bool 確實包含bool類變量中預期的兩個值之一,因為 C 和 C++ 沒有真正的bool類型,我們用int偽造了它。 現在對於“真正的” bool s,這不是一個問題。

但是使用!! 是一種有效的記錄方式(對於編譯器和任何未來在您的代碼中工作的人),是的,您確實打算將該int轉換為bool

使用它是因為 C 語言(以及一些預標准的 C++ 編譯器)沒有bool類型,只有int 所以int被用來表示邏輯值: 0應該表示false ,其他一切都是true ! 運算符返回1 ,從00的一切。 ! 被用來反轉這些,它在那里確保值只是01具體取決於其邏輯值。

在 C++ 中,由於引入了適當的bool類型,因此不再需要這樣做。 但是,由於 C 與 C++ 的向后兼容性(大多數情況下),您不能只更新所有遺留源,而且您也不應該這樣做。 但是很多人仍然這樣做,出於同樣的原因:保持他們的代碼向后兼容仍然不理解bool的舊編譯器。

這是唯一真正的答案。 其他答案具有誤導性。

因為 !integerValue 意味着 integerValue == 0 並且 !!integerValue 因此意味着 integerValue != 0,一個返回 bool 的有效表達式。 后者是信息丟失的演員表。

另一種選擇是三元運算符,它似乎生成的匯編代碼少一行(無論如何在 Visual Studio 2005 中):

bool ternary_test = ( int_val == 0 ) ? false : true;

產生匯編代碼:

cmp DWORD PTR _int_val$[ebp], 0
setne   al
mov BYTE PTR _ternary_test$[ebp], al

相對:

bool not_equal_test = ( int_val != 0 );

它產生:

xor eax, eax
cmp DWORD PTR _int_val$[ebp], 0
setne   al
mov BYTE PTR _not_equal_test$[ebp], al

我知道這不是一個巨大的差異,但我對此很好奇,只是想我會分享我的發現。

bool 只能有 0 和 1 兩種狀態。假設有符號的 32 位整數,整數可以具有從 -2147483648 到 2147483647 的任何狀態。 一元! 如果輸入為 0,則運算符輸出 1,如果輸入為 0 以外的任何內容,則輸出 0。因此 !0 = 1 且 !234 = 0。第二個 ! 簡單地切換輸出,使 0 變為 1,1 變為 0。

因此,第一條語句保證 booleanValue 將被設置為等於 0 或 1 且沒有其他值,第二條語句則不然。

!! 是轉換為bool的慣用方式,它可以關閉 Visual C++ 編譯器關於此類轉換效率低下的愚蠢警告。

我從其他答案和評論中看到,很多人不熟悉這個習語在 Windows 編程中的用處。 這意味着他們沒有做過任何嚴肅的 Windows 編程。 並盲目地假設他們遇到的事情具有代表性(事實並非如此)。

#include <iostream>
using namespace std;

int main( int argc, char* argv[] )
{
    bool const b = static_cast< bool >( argc );
    (void) argv;
    (void) b;
}
> [d:\dev\test]
> cl foo.cpp
foo.cpp
foo.cpp(6) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)

[d:\dev\test]
> _

至少有一個人認為,如果一個徹頭徹尾的新手不認識它的含義,那就不好了。 嗯,這很愚蠢。 有很多完全是新手不認識或不理解的。 編寫一個代碼以便任何新手都能理解它並不是專業人士的事情。 甚至不適合學生。 從排除完全新手不認識的運算符和運算符組合的路徑開始......好吧,我沒有詞來給這種方法一個適當的描述,抱歉。

user143506 的答案是正確的,但對於可能的性能問題,我比較了 asm 中的可能性:

return x; , return x != 0; , return !!x; 甚至return boolean_cast<bool>(x)結果在這組完美的 asm 指令中:

test    edi/ecx, edi/ecx
setne   al
ret

這已針對 GCC 7.1 和 MSVC 19 2017 進行了測試。(只有 MSVC 19 2017 中的 boolean_converter 導致更多的 asm 代碼,但這是由模板化和結構引起的,從性能的角度來看可以忽略不計,因為相同上面提到的行可能只是為具有相同運行時的不同函數重復。)

這意味着:沒有性能差異。

PS:使用了這個 boolean_cast:

#define BOOL int
// primary template
template< class TargetT, class SourceT >
struct boolean_converter;

// full specialization
template< >
struct boolean_converter<bool, BOOL>
{
  static bool convert(BOOL b)
  {
    return b ? true : false;
  }
};

// Type your code here, or load an example.
template< class TargetT, class SourceT >
TargetT boolean_cast(SourceT b)
{
  typedef boolean_converter<TargetT, SourceT> converter_t;
  return converter_t::convert(b);
}

bool is_non_zero(int x) {
   return boolean_cast< bool >(x);
}

除了偏執或通過代碼大喊它是一個布爾之外,沒有什么大的理由。

對於編譯器最終它不會有所作為。

我從不喜歡這種轉換為bool數據類型的技術——它聞起來不對!

相反,我們使用了一個名為boolean_cast的便捷模板, boolean_cast此處找到。 這是一個靈活的解決方案,它在做什么方面更加明確,可以按如下方式使用:

bool IsWindow = boolean_cast< bool >(::IsWindow(hWnd));

暫無
暫無

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

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