Waarom !! bij het converteren van int naar bool?

Wat kan een reden zijn om een ​​geheel getal op deze manier naar een boolean te converteren?

bool booleanValue = !!integerValue;

in plaats van alleen

bool booleanValue = integerValue;

Alles wat ik weet is dat in VC++7 dit laatste C4800-waarschuwing en de eerste niet. Is er een ander verschil tussen de twee?


Antwoord 1, autoriteit 100%

De problemen met de “!!” idioom is dat het beknopt is, moeilijk te zien, gemakkelijk te verwarren met een typefout, gemakkelijk een van de “!’s” te laten vallen, enzovoort. Ik plaatste het in de categorie “kijk hoe schattig we kunnen zijn met C/C++”.

Schrijf gewoon bool isNonZero = (integerValue != 0);… wees duidelijk.


Antwoord 2, autoriteit 43%

Historisch gezien werd het !!idioom gebruikt om ervoor te zorgen dat je bool echt een van de twee waarden bevatte die verwacht werden in een bool-achtige variabele, omdat C en C++ dat niet deden. ‘t hebben geen echt bool-type en we hebben het vervalst met ints. Dit is nu minder een probleem met “echte” bools.

Maar het gebruik van !!is een efficiënte manier om te documenteren (zowel voor de compiler als voor toekomstige mensen die in je code werken) dat ja, je echt van plan was om die intnaar een bool.


Antwoord 3, autoriteit 13%

Het wordt gebruikt omdat de C-taal (en sommige pre-standaard C++-compilers ook) niet het type boolhadden, alleen int. Dus de ints werden gebruikt om logische waarden weer te geven: 0moest falsebetekenen, en al het andere was true. De operator !retourneerde 1van 0en 0van al het andere. Dubbel !werd gebruikt om die om te keren, en het was er om ervoor te zorgen dat de waarde slechts 0of 1is, afhankelijk van de logische waarde.

In C++ is het, sinds de introductie van een juist bool-type, niet meer nodig. Maar je kunt niet zomaar alle legacy-bronnen bijwerken, en dat zou ook niet moeten, vanwege achterwaartse compatibiliteit van C met C++ (meestal). Maar veel mensen doen het nog steeds, om dezelfde reden: om hun code achterwaarts compatibel te houden met oude compilers die bools nog steeds niet begrijpen.

En dit is het enige echte antwoord. Andere antwoorden zijn misleidend.


Antwoord 4, autoriteit 11%

Omdat !integerValue integerValue == 0 betekent en !!integerValue dus integerValue != 0 betekent, een geldige expressie die een bool retourneert. De laatste is een cast met informatieverlies.


Antwoord 5, autoriteit 6%

Een andere optie is de ternaire operator die een regel minder assembly-code lijkt te genereren (in ieder geval in Visual Studio 2005):

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

die de assembly-code produceert:

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

Versus:

bool not_equal_test = ( int_val != 0 );

die produceert:

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

Ik weet dat het geen enorm verschil is, maar ik was er nieuwsgierig naar en dacht dat ik mijn bevindingen zou delen.


Antwoord 6, autoriteit 4%

Een bool kan maar twee toestanden hebben, 0 en 1. Een geheel getal kan elke toestand hebben van -2147483648 tot 2147483647, uitgaande van een 32-bits geheel getal met teken. De unaire! operator voert 1 uit als de invoer 0 is en voert 0 uit als de invoer iets anders is dan 0. Dus !0 = 1 en !234 = 0. De tweede ! schakelt eenvoudig de uitgang zodat 0 1 wordt en 1 0 wordt.

Dus het eerste statement garandeert dat booleanValue gelijk is aan 0 of 1 en geen andere waarde, het tweede statement niet.


Antwoord 7, autoriteit 4%

!!is een idiomatische manier om te converteren naar bool, en het werkt om de domme waarschuwing van de Visual C++-compiler over vermeende inefficiëntie van een dergelijke conversie de mond te snoeren.

Ik zie aan de andere antwoorden en opmerkingen dat veel mensen niet bekend zijn met het nut van dit idioom in Windows-programmering. Wat betekent dat ze geen serieuze Windows-programmering hebben gedaan. En ga er blindelings vanuit dat wat ze zijn tegengekomen representatief is (dat is het niet).

#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) : waarschuwing C4800: 'int' : waarde forceren om 'true' of 'false' te bool (prestatiewaarschuwing)
[d:\dev\test]
> _

En minstens één persoon denkt dat als een volslagen beginner de betekenis niet herkent, het slecht is. Nou dat is dom. Er is veel dat absolute beginners niet herkennen of begrijpen. Het schrijven van een code zodat deze door elke absolute beginner wordt begrepen, is niet iets voor professionals. Ook niet voor studenten. Beginnend op het pad van het uitsluiten van operatoren en operatorcombinaties die absolute beginners niet herkennen… Nou, ik heb geen woorden om die benadering een passende beschrijving te geven, sorry.


Antwoord 8

Het antwoord van user143506 is correct, maar voor een mogelijk prestatieprobleem heb ik de mogelijkheden in asm vergeleken:

return x;, return x != 0;, return !!x;en zelfs return boolean_cast<bool>(x)resulteert in deze perfecte set van asm-instructies:

test    edi/ecx, edi/ecx
setne   al
ret

Dit is getest voor GCC 7.1 en MSVC 19 2017. (Alleen de boolean_converter in MSVC 19 2017 resulteert in een grotere hoeveelheid asm-code, maar dit wordt veroorzaakt door templatisatie en structuren en kan worden verwaarloosd vanuit het oogpunt van prestaties, omdat dezelfde regels als hierboven vermeld mogelijk worden gedupliceerd voor verschillende functies met dezelfde looptijd.)

Dit betekent: er is geen prestatieverschil.

PS: Deze boolean_cast is gebruikt:

#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);
}

Antwoord 9

Geen grote reden behalve paranoïde zijn of door code schreeuwen dat het een bool is.

voor de compiler maakt het uiteindelijk geen verschil .


Antwoord 10

Ik heb deze techniek van het converteren naar een bool-gegevenstype nooit leuk gevonden – het ruikt verkeerd!

In plaats daarvan gebruiken we een handig sjabloon genaamd boolean_castgevonden hier. Het is een flexibele oplossing die explicieter is in wat het doet en als volgt kan worden gebruikt:

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

Other episodes