Pertanyaan Mengapa menggunakan !! saat mengkonversi int ke bool?


Apa yang bisa menjadi alasan untuk mengonversi bilangan bulat ke boolean dengan cara ini?

bool booleanValue = !!integerValue;

bukan hanya

bool booleanValue = integerValue;

Yang saya tahu adalah bahwa dalam VC ++ 7 yang terakhir akan menyebabkan Peringatan C4800  dan yang pertama tidak. Apakah ada perbedaan lain di antara keduanya?


75
2017-08-21 06:36


asal


Jawaban:


Masalah dengan "!!" idiom adalah bahwa itu singkat, sulit untuk melihat, mudah kesalahan untuk salah ketik, mudah untuk menjatuhkan salah satu dari "!", dan sebagainya. Saya memasukkannya ke dalam kategori "lihat seberapa imut kita bisa dengan C / C ++".

Tulis saja bool isNonZero = (integerValue != 0); ... jadilah jelas.


110
2017-08-21 07:06



Secara historis, !! idiom digunakan untuk memastikan bahwa bool Anda benar-benar berisi salah satu dari dua nilai yang diharapkan dalam bool-seperti variabel, karena C dan C ++ tidak memiliki true bool ketik dan kami memalsukannya ints. Ini bukan masalah sekarang dengan "nyata" bools.

Tetapi menggunakan !! adalah cara yang efisien untuk mendokumentasikan (baik untuk compiler dan orang-orang di masa depan yang bekerja dalam kode Anda) bahwa ya, Anda benar-benar berniat untuk membuangnya int ke a bool.


49
2017-08-21 06:41



Karena! IntegerValue berarti integerValue == 0 dan !! integerValue dengan demikian berarti integerValue! = 0, ekspresi valid yang mengembalikan bool. Yang terakhir adalah pemain dengan kehilangan informasi.


13
2017-08-21 06:38



Ini digunakan karena bahasa C (dan beberapa compiler C ++ pra-standar juga) tidak memiliki bool tipe, adil int. Sehingga ints digunakan untuk mewakili nilai-nilai logis: 0 seharusnya berarti false, dan yang lainnya true. Itu ! operator kembali 1 dari 0 dan 0 dari yang lainnya. Dua kali lipat ! digunakan untuk membalikkan mereka, dan itu ada di sana untuk memastikan bahwa nilainya adil 0 atau 1 tergantung pada nilai logisnya.

Di C ++, sejak memperkenalkan yang tepat bool ketik, tidak perlu melakukan itu lagi. Tetapi Anda tidak bisa hanya memperbarui semua sumber warisan, dan Anda tidak harus, karena kompatibilitas C dengan C ++ (sebagian besar waktu). Tetapi banyak orang masih melakukannya, dari alasan yang sama: untuk tetap menggunakan kode mereka yang kompatibel dengan kompiler lama yang masih tidak mengerti bools.

Dan inilah satu-satunya jawaban yang nyata. Jawaban lainnya menyesatkan.


13
2017-08-28 09:58



Pilihan lain adalah operator terner yang tampaknya menghasilkan satu baris kurang dari kode assembly (dalam Visual Studio 2005 anyways):

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

yang menghasilkan kode assembly:

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

Melawan:

bool not_equal_test = ( int_val != 0 );

yang menghasilkan:

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

Saya tahu ini bukan perbedaan besar tetapi saya ingin tahu tentang itu dan hanya berpikir bahwa saya akan berbagi temuan saya.


6
2017-09-12 17:11



Bool hanya dapat memiliki dua status, 0, dan 1. Sebuah bilangan bulat dapat memiliki status apa pun dari -2147483648 hingga 2147483647 dengan asumsi bilangan bulat 32-bit yang ditandatangani. The unary! output operator 1 jika input adalah 0 dan output 0 jika input adalah apa pun kecuali 0. Jadi! 0 = 1 dan! 234 = 0. Yang kedua! hanya beralih output sehingga 0 menjadi 1 dan 1 menjadi 0.

Jadi pernyataan pertama menjamin bahwa booleanValue akan ditetapkan sama dengan 0 atau 1 dan tidak ada nilai lain, pernyataan kedua tidak.


5
2017-08-21 06:48



!!adalah cara idiomatis untuk mengonversi bool, dan bekerja untuk menutup pengacakan silly Visual C ++ kompilator tentang dugaan ketidakefisienan konversi tersebut.

Saya melihat dengan jawaban dan komentar lain yang banyak orang tidak akrab dengan kegunaan idiom ini dalam pemrograman Windows. Yang berarti mereka belum melakukan pemrograman Windows yang serius. Dan berasumsi secara membuta bahwa apa yang mereka temui adalah representatif (tidak demikian).

#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): peringatan C4800: 'int': memaksa nilai ke bool 'true' atau 'false' (peringatan kinerja)

[d: \ dev \ test]
> _

Dan setidaknya satu orang berpikir bahwa jika seorang pemula mengucapkan tidak mengenali maknanya, maka itu tidak baik. Itu bodoh. Ada banyak yang mengucapkan novis tidak mengenali atau mengerti. Menuliskan kode seseorang sehingga itu akan dimengerti oleh setiap pemula adalah bukan sesuatu yang profesional. Bahkan untuk siswa. Mulai di jalur yang tidak termasuk operator dan kombinasi operator yang membuat pemula tidak mengenali ... Yah, saya tidak memiliki kata-kata untuk memberikan pendekatan itu deskripsi yang sesuai, maaf.

Cheers & Hth.,


4
2017-11-19 07:56



Jawaban dari user143506 benar tetapi untuk kemungkinan masalah kinerja saya membandingkan kemungkinan dalam asm:

return x;, return x != 0;, return !!x; dan bahkan return boolean_cast<bool>(x) hasilkan set instruksi asm yang sempurna ini:

test    edi/ecx, edi/ecx
setne   al
ret

Ini diuji untuk GCC 7.1 dan MSVC 19 2017. (Hanya boolean_converter di MSVC 19 2017 menghasilkan jumlah yang lebih besar dari kode-asm tetapi ini disebabkan oleh templatization dan struktur dan dapat diabaikan oleh sudut pandang kinerja, karena sama baris seperti yang disebutkan di atas mungkin hanya diduplikasi untuk fungsi yang berbeda dengan runtime yang sama.)

Ini berarti: Tidak ada perbedaan kinerja.

PS: boolean_cast ini digunakan:

#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
2017-11-27 11:09



Tidak ada alasan besar kecuali menjadi paranoid atau berteriak melalui kode yang bool-nya.

untuk compiler pada akhirnya tidak akan membuat perbedaan.


-1
2017-08-21 07:13