2009-08-21 23 views
73

Điều gì có thể là lý do để chuyển đổi một số nguyên thành boolean theo cách này?Tại sao nên sử dụng !! khi chuyển đổi int để bool?

bool booleanValue = !!integerValue; 

thay vì chỉ

bool booleanValue = integerValue; 

Tất cả tôi biết là trong VC++ 7 sau này sẽ gây C4800 warning và cựu sẽ không. Có sự khác biệt nào khác giữa hai người không?

+2

Tôi đoán câu hỏi là tại sao trước đây không gây ra một C4800 hoặc kể từ khi thậm chí là "Đúc các biểu thức để gõ bool sẽ không vô hiệu hóa các cảnh báo, đó là bởi thiết kế. " (MS) – Tobias

+0

um, điều này thực sự có vị trí của nó ... mọi người đang bối rối C++ và C –

+2

Sau khi phủ định kép, giá trị được đảm bảo là 0 hoặc 1; giá trị ban đầu có thể là bất kỳ giá trị int nào. –

Trả lời

108

Sự cố với "!!" thành ngữ là nó thật khó hiểu, khó nhìn, dễ nhầm lẫn với lỗi đánh máy, dễ dàng thả một trong những "!", v.v. Tôi đặt nó vào thể loại "trông dễ thương với C/C++".

Chỉ cần viết bool isNonZero = (integerValue != 0); ... hãy rõ ràng.

+9

+1 cho "bool isNonZero = (integerValue! = 0);". Tôi luôn luôn ghét nó khi mã conflates ints, tăng gấp đôi, ptrs, vv với bool's. Họ là những loại khác nhau và nên được đối xử như vậy. Các diễn viên tiềm ẩn của một bool để loại số là một sự không đồng bộ. –

+8

Tôi không thấy một vấn đề với việc xử lý int/con trỏ như bools - đó là một thành phần chứng khoán C/C++, và bất kỳ nhà phát triển thành thạo trong họ nên được dự kiến ​​sẽ biết nó. Tuy nhiên, đôi khi bạn muốn tránh cảnh báo trình biên dịch và như vậy - và trong những trường hợp đó, một sự so sánh hoàn toàn (hoặc một diễn viên) chắc chắn là thích hợp hơn nhiều đối với thủ thuật '!!' khá mơ hồ. –

+0

Ints và bools là khác nhau. Tại sao nên 0 == sai. Đó là một nôn nao từ những ngày trước khi loại bool. Nó cũng có nghĩa là !! a không nhất thiết phải bằng với tính năng phản trực giác. –

13

Vì! IntegerValue có nghĩa là integerValue == 0 và !! integerValue nghĩa là integerValue! = 0, một biểu thức hợp lệ trả về một bool. Sau này là một diễn viên với mất thông tin.

49

Trong lịch sử, !! thành ngữ được sử dụng để đảm bảo rằng bool của bạn thực sự chứa một trong hai giá trị dự kiến ​​trong một biến -like bool, vì C và C++ không có một sự thật bool loại và chúng tôi giả nó với int s . Đây là vấn đề ít hơn bây giờ với "thực" bool s.

Nhưng sử dụng !! là một phương tiện hiệu quả của tài liệu (đối với cả hai trình biên dịch và bất kỳ người trong tương lai làm việc trong mã của bạn) mà có, bạn thực sự có ý định đúc mà int đến một bool.

+9

Tôi sẽ không nói "một phương tiện hiệu quả của tài liệu" nếu OP thậm chí không hiểu những gì nó có nghĩa là. Một cách tốt hơn sẽ là static_cast (integerValue). – arolson101

+10

OP có lẽ không biết 'Danh sách ' có nghĩa là gì lúc đầu, hoặc là '|| ='. '!!' là một thành ngữ vô cùng sâu sắc trong vũ trụ C và C++. Nếu bất cứ ai không biết điều đó, anh/cô ấy nên học nó - và sau đó đưa ra đánh giá lý luận của riêng họ về việc liệu có nên sử dụng nó hay không. –

+5

có gì sai với 'bool var = (bool) intVar;'? – bobobobo

5

Một bool chỉ có thể có hai trạng thái, 0 và 1. Một số nguyên có thể có trạng thái bất kỳ từ -2147483648 đến 2147483647 giả sử số nguyên 32 bit đã ký. Các unary! đầu ra của nhà điều hành 1 nếu đầu vào là 0 và đầu ra 0 nếu đầu vào là bất cứ điều gì ngoại trừ 0. Vì vậy, 0 = 1 và! 234 = 0. Thứ hai! chỉ cần chuyển đổi đầu ra để 0 trở thành 1 và 1 trở thành 0.

Vì vậy, câu lệnh đầu tiên đảm bảo rằng booleanValue sẽ được đặt bằng 0 hoặc 1 và không có giá trị khác, câu lệnh thứ hai thì không.

+2

Điều này hoàn toàn sai. Câu lệnh thứ hai liên quan đến một 'int'->' bool'. Điều này được xác định rõ, và bất kỳ số không 'int' nào khác sẽ được chuyển thành' true', và 0 sẽ được chuyển thành 'false'. Cảnh báo mà VC++ đưa ra ở đó thực sự là "cảnh báo hiệu suất" và không liên quan gì đến điều này. –

+0

Tôi nghĩ rằng bạn đang bối rối BOOL với bool. Với bool, bạn sẽ có được một bool thực với một diễn viên ngầm, do đó đúng hoặc sai. – Recep

+2

Các trạng thái của một bool trong C++ không phải là 1 và 0, nhưng đúng và sai. –

-1

Không có lý do chính nào ngoại trừ việc hoang tưởng hoặc la hét thông qua mã là một bool.

cho trình biên dịch cuối cùng nó sẽ không tạo sự khác biệt.

+0

Mã được tạo cũng có thể là "chậm hơn": số nguyên sẽ yêu cầu thử nghiệm để xem nó có bằng không. Tuy nhiên, đối với một boolean được biểu diễn dưới dạng nhị phân 0/1, không cần kiểm tra. –

+2

Nhưng, tốt, với lý trí này, chúng ta nên có một cảnh báo hiệu suất cho mỗi cuộc gọi chức năng ảo ... – gimpf

+0

Bạn có thể muốn đọc rằng: http://stackoverflow.com/a/1847949/62921 – ForceMagic

-2

Tôi chưa bao giờ thích kỹ thuật chuyển đổi thành kiểu dữ liệu bool - nó có mùi sai!

Thay vào đó, chúng tôi đang sử dụng mẫu tiện dụng được gọi là boolean_cast được tìm thấy here. Đó là một giải pháp linh hoạt đó là rõ ràng hơn trong những gì nó làm và có thể sử dụng như sau:

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

Đó là một chút của một overkill phải không? Tôi có nghĩa là vào cuối ngày chuyển đổi để bool là một sự mất mát trong chính xác và sôi xuống một cái gì đó như trở lại b? đúng sai; Đó là về giống như !! TRUE Cá nhân này là overengineered STL giống như fetish. –

+0

Tôi lấy nó bạn không đồng ý với việc sử dụng boolean_cast sau đó (do đó bỏ phiếu xuống) - bạn sẽ đề nghị chúng ta sử dụng cái gì sau đó? – Alan

+4

Tôi đề nghị bạn sử dụng ngôn ngữ như nó đã được sử dụng. Hiệu suất cao và khó chịu. Chỉ cần cắt BS và hoàn thành công việc. –

4

!! là một cách thành ngữ để chuyển đổi sang bool, và nó hoạt động để im lặng sillywarning C trực quan ++ biên dịch về cáo buộc thiếu hiệu quả của ví dụ chuyển đổi.

Tôi thấy các câu trả lời và nhận xét khác mà nhiều người không quen thuộc với tính hữu dụng của thành ngữ này trong lập trình Windows. Điều đó có nghĩa là họ chưa thực hiện bất kỳ chương trình Windows nghiêm túc nào. Và giả sử một cách mù quáng rằng những gì họ gặp phải là đại diện (nó không phải là).

#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] 
> _ 

Và ít nhất một người nghĩ rằng nếu một người mới hoàn toàn không nhận ra ý nghĩa của nó, sau đó nó ungood. Vâng đó là ngu ngốc. Có rất nhiều người mới hoàn toàn không nhận ra hoặc hiểu. Viết mã của một người để nó sẽ được hiểu bởi bất kỳ người mới hoàn toàn không phải là một cái gì đó cho các chuyên gia. Ngay cả đối với sinh viên. Bắt đầu trên con đường loại trừ các toán tử và kết hợp toán tử mà người mới hoàn toàn không nhận ra ... Tôi không có từ để đưa ra cách tiếp cận đó một mô tả thích hợp, xin lỗi.

Cheers & h.,

13

Nó được sử dụng bởi vì ngôn ngữ C (và một số tiền tiêu chuẩn C++ biên dịch quá) không có các loại bool, chỉ int. Vì vậy, int s được sử dụng để biểu thị các giá trị logic: 0 được cho là có nghĩa là false và mọi thứ khác là true. Nhà điều hành ! đã trả lại 1 từ 00 từ mọi thứ khác. Double ! được sử dụng để đảo ngược chúng, và nó đã có để đảm bảo rằng giá trị chỉ là 0 hoặc 1 tùy thuộc vào giá trị logic của nó.

Trong C++, vì giới thiệu loại bool thích hợp, không cần phải làm điều đó nữa. Nhưng bạn không thể chỉ cập nhật tất cả các nguồn cũ, và bạn không cần phải, do khả năng tương thích ngược của C với C++ (phần lớn thời gian). Nhưng nhiều người vẫn làm điều đó, từ cùng một lý do: duy trì mã của họ tương thích ngược với các trình biên dịch cũ mà vẫn không hiểu được bool s.

Và đây là câu trả lời thực sự duy nhất. Các câu trả lời khác là gây hiểu nhầm.

+0

Điều đó thật rõ ràng. +1 :) – zx81

6

lựa chọn khác là các nhà điều hành ternary mà dường như tạo ra một dòng ít mã lắp ráp (trong Visual Studio 2005 anyways):

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

trong đó sản xuất mã lắp ráp:

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

Versus:

bool not_equal_test = (int_val != 0); 

sản xuất:

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

Tôi biết nó không phải là một sự khác biệt lớn nhưng tôi đã tò mò về nó và chỉ nghĩ rằng tôi sẽ chia sẻ những phát hiện của tôi.

1

Câu trả lời của user143506 là đúng nhưng đối với một vấn đề hiệu suất có thể, tôi đã so sánh possibilies trong asm:

return x;, return x != 0;, return !!x; và thậm chí return boolean_cast<bool>(x) kết quả trong bộ này hoàn hảo của hướng dẫn asm:

test edi/ecx, edi/ecx 
setne al 
ret 

Điều này đã được thử nghiệm cho GCC 7.1 và MSVC 19 2017. (Chỉ có boolean_converter trong MSVC 19 2017 dẫn đến số lượng mã asm lớn hơn nhưng điều này gây ra bởi sự biến đổi và cấu trúc và có thể bị bỏ qua bởi quan điểm thực hiện, vì cùng một lin es như đã lưu ý ở trên có thể chỉ được nhân bản cho các hàm khác nhau với cùng một thời gian chạy.)

Điều này có nghĩa là: Không có sự khác biệt về hiệu suất.

PS: boolean_cast này đã được sử dụng:

#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); 
} 
Các vấn đề liên quan