Tại sao sử dụng !! khi chuyển đổi int thành bool?


76

Điều gì có thể là lý do để chuyển đổi một số nguyên thành một boolean theo cách này?

bool booleanValue = !!integerValue;

Thay vì chỉ

bool booleanValue = integerValue;

Tất cả những gì tôi biết là trong VC ++ 7, cái sau sẽ gây ra cảnh báo C4800 và cái trước thì không. Có sự khác biệt nào khác giữa hai?


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.
Martin kiện Löwis

1
Nhưng tại sao câu lệnh thứ hai sẽ không làm chính xác như vậy?
sharptooth

2
Tôi đoán câu hỏi là tại sao trước đây không gây ra C4800 vì ngay cả "Truyền biểu thức để nhập bool sẽ không vô hiệu hóa cảnh báo, đó là do thiết kế." (MS)
Tobias

2
tại sao nhiều người không hiểu rằng đây là câu trả lời chính xác. đôi tiêu cực là rất phổ biến trong mã cấp thấp
Matt Joiner

um, điều này thực sự có nó diễn ra ... mọi người đang bối rối C ++ và C
Matt Joiner

Câu trả lời:


112

Các vấn đề với dấu "!!" thành ngữ ngắn gọn, khó nhìn, dễ sai lỗi chính tả, dễ bỏ một trong các dấu "! 's", v.v. Tôi đưa nó vào danh mục "trông chúng ta dễ thương làm sao với C / C ++".

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


11
+1 cho "bool isNonZero = (integerValue! = 0);". Tôi luôn ghét nó khi mã kết hợp ints, double, ptrs, v.v. với bool's. Chúng là các loại khác nhau và nên được đối xử như vậy. Việc chuyển kiểu ngầm từ bool sang kiểu số là một trường phái Anchronism.
jon-hanson

8
Tôi không thấy có vấn đề gì với việc coi ints / pointers như bools - đó là một thành ngữ C / C ++ cổ phiếu và bất kỳ nhà phát triển nào thành thạo về chúng đều phải biết điều đó. Tuy nhiên, đôi khi bạn muốn tránh các cảnh báo của trình biên dịch và những điều đó - và trong những trường hợp đó, so sánh rõ ràng (hoặc một dàn diễn viên) chắc chắn sẽ thích hợp hơn nhiều so với !!thủ thuật tương đối mù mờ .
Pavel Minaev

3
0 bằng false vì tiêu chuẩn nói như vậy ;-) !! là một thành ngữ khá phổ biến mà bạn dường như không quen thuộc. Điều đó không làm cho nó trở nên tồi tệ liên tục, ngoại trừ việc sử dụng ở đầu câu ngôn ngữ tự nhiên.
Gunther Piez

16
+1 cho "xem chúng ta có thể trở nên dễ thương như thế nào với C / C ++". Tổng hợp hoàn hảo rất nhiều thực hành mã hóa tồi mà cú pháp C / C ++ và các quy tắc lỏng lẻo cho phép.
David

8
-1 cho "bool isNonZero = (integerValue! = 0);", điều này không dễ đọc hơn cũng không "trực quan" hơn. Nếu bạn không thích các thành ngữ C / C ++ tiêu chuẩn như !!, hãy sử dụng một ngôn ngữ khác.
Gunther Piez

49

Trong lịch sử, !!thành ngữ này đượ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ị được mong đợi trong một boolbiến -like, bởi vì C và C ++ không có boolkiểu true và chúng tôi đã giả mạo nó bằng ints. Bây giờ điều này ít là một vấn đề với "thực" bool.

Nhưng việc sử dụng !!là một phương tiện hiệu quả để ghi lại tài liệu (cho cả trình biên dịch và bất kỳ người nào trong tương lai làm việc trong mã của bạn) rằng có, bạn thực sự đã có ý định truyền nó intthành a bool.


10
Tôi sẽ không nói "một phương tiện ghi tài liệu hiệu quả" nếu OP thậm chí không hiểu ý nghĩa của nó. Một cách tốt hơn nhiều sẽ là static_cast <bool> (integerValue).
arolson101

10
OP có lẽ lúc đầu cũng không biết List<String>nghĩa là gì , hoặc ||=. !!là một thành ngữ đã ăn sâu vào thế giới C và C ++. Nếu ai chưa biết nó, họ nên tìm hiểu nó - và sau đó đưa ra đánh giá hợp lý của riêng họ về việc có nên sử dụng nó hay không.
TJ Crowder

@ arolson, @ TJ Crowder: !! có thể hiệu quả, nhưng nó không hiệu quả
Lie Ryan

Một bool "thực" có thể có nhiều hơn hai giá trị không? Ví dụ, kết quả của (bool) 1 ^ (bool) 2 Nó là 0 hay 3?
dspyz

1
@ arolson101: static_cast <bool> (integerValue) là một cảnh báo trong VSCPP 2015 (v14). Nếu cảnh báo lỗi cho bạn (hoặc cho người xem mã của bạn), bạn đang trên may mắn w / that ...
lorro

14

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

Trong C ++, kể từ khi giới thiệu một boolkiểu 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 kế thừa và bạn không cần phải làm vậy, do khả năng tương thích ngược của C với C ++ (hầu hết thời gian). Nhưng nhiều người vẫn làm điều đó, vì lý do tương tự: để 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.

Và đây là câu trả lời thực sự duy nhất. Các câu trả lời khác là sai lệch.


13

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


7

Một tùy chọn khác là toán tử bậc ba dường như tạo ra ít hơn một dòng mã lắp ráp (trong Visual Studio 2005 bất kỳ):

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

tạo ra mã lắp ráp:

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

Đấu với:

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 mình.


5

Một bool chỉ có thể có hai trạng thái, 0 và 1. Một số nguyên có thể có bất kỳ trạng thái nào từ -2147483648 đến 2147483647 giả sử là số nguyên 32 bit có dấu. Hoàng đế! toán tử đầu ra 1 nếu đầu vào là 0 và đầu ra 0 nếu đầu vào là bất kỳ thứ gì ngoại trừ 0. Vì vậy! 0 = 1 và! 234 = 0. Thứ hai! chỉ cần chuyển đầ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ị nào khác, câu lệnh thứ hai thì không.


2
Điều này là hoàn toàn sai lầm. Câu lệnh thứ hai liên quan đến một ẩn int-> boolép kiểu. Điều này được xác định rõ và bất kỳ giá trị nào khác 0 intsẽ được chuyển đổi thành truevà 0 sẽ được chuyển thành false. Cảnh báo mà VC ++ đưa ra thực sự là một "cảnh báo hiệu suất", và không liên quan gì đến điều này.
Pavel Minaev

Tôi nghĩ bạn đang nhầm lẫn giữa BOOL với bool. Với bool, bạn sẽ nhận được bool thực sự với một kiểu ẩn, do đó đúng hoặc sai.
Recep

2
Các trạng thái của bool trong C ++ không phải là 1 và 0, mà là true và false.
Johannes Schaub - litb

Cảm ơn bạn, tôi không biết điều đó. Tôi nghĩ rằng 0 == false và 1 == true nhưng rõ ràng là không phải như vậy.
John Scipione

bạn đã đúng trong lần đầu tiên john scipione, điều này đã xảy ra
Matt Joiner

4

!! là một cách thành ngữ để chuyển đổi thành bool và nó hoạt động để ngăn chặn lời cảnh báo ngớ ngẩn của trình biên dịch Visual C ++ về sự kém hiệu quả được cho là của việc chuyển đổi như vậy.

Qua các câu trả lời và nhận xét khác, nhiều người không quen với tính hữu dụng của thành ngữ này trong lập trình Windows. Có nghĩa là họ chưa thực hiện bất kỳ lập trình Windows nghiêm túc nào. Và giả định 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).

#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': buộc giá trị thành bool 'true' hoặc 'false' (cảnh báo hiệu suất)

[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ó, thì đó là điều không tốt. Chà, thật là ngu ngốc. Có rất nhiều điều mà người mới hoàn toàn không nhận ra hoặc không 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 nào không phải là điều dành cho các chuyên gia. Ngay cả đối với sinh viên cũng không. Bắt đầu trên con đường loại trừ các toán tử và 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ừ để cung cấp cho cách tiếp cận đó một mô tả thích hợp, xin lỗ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ể xảy ra, tôi đã so sánh các khả năng 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ỉ boolean_converter trong MSVC 19 2017 dẫn đến lượng mã asm lớn hơn nhưng điều này là do quá trình tạo khuôn mẫu và cấu trúc gây ra và có thể bị bỏ qua bởi quan điểm hiệu suất, vì cùng các dòng như đã lưu ý ở trên có thể chỉ bị trùng lặp cho các chức năng khác nhau với cùng 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);
}

-1

Không có lý do gì lớn ngoại trừ việc bị hoang tưởng hoặc la hét qua mã rằng đó là một món hời.

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


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

2
Nhưng, cũng với lý 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

-2

Tôi chưa bao giờ thích kỹ thuật chuyển đổi sang boolkiểu dữ liệu này - nó có vẻ sai!

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

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

8
Nó hơi quá mức cần thiết phải không? Ý tôi là vào cuối ngày chuyển đổi thành bool là mất độ chính xác và sôi xuống một cái gì đó như return b? đúng sai; Điều đó giống như !! ĐÚNG Cá nhân đây là sự tôn sùng giống STL được khai thác quá mức.
Igor Zevaka

Tôi hiểu rằng bạn không đồng ý với việc sử dụng boolean_cast sau đó (do đó bỏ phiếu phản đối) - bạn sẽ đề nghị chúng tôi sử dụng gì sau đó?
Alan

5
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.
Matt Joiner
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.