Зачем использовать! при конвертации int в bool?
что может быть причиной для преобразования целого числа в булево таким образом?
bool booleanValue = !!integerValue;
вместо
bool booleanValue = integerValue;
все, что я знаю, это то, что в VC++7 последнее вызовет C4800 предупреждение а первый не будет. Есть ли еще какая-то разница между ними?
10 ответов:
проблемы с "!!"идиома заключается в том, что это кратко, трудно увидеть, легко ошибиться для опечатки, легко уронить один из "!'S", и так далее. Я поместил его в категорию" посмотрите, как мило мы можем быть с C/C++".
Просто напишитеbool isNonZero = (integerValue != 0);
... быть ясным.
исторически
!!
идиома была использована для того, чтобы убедиться, что ваш bool действительно содержит одно из двух значений, ожидаемых вbool
-как переменная, потому что C и C++ не было truebool
тип и мы подделали его сint
s. теперь это меньше проблема с "Реалом"bool
s., но через
!!
является эффективным средством документирования (как для компилятора, так и для любых будущих людей, работающих в вашем коде), что да, вы действительно намеревались бросить этоint
вbool
.
он используется потому, что язык C (и некоторые предустановленные компиляторы C++ тоже) не имели
bool
тип, простоint
. Так чтоint
s использовались для представления логических значений:0
должно было означатьfalse
, и все остальное былоtrue
. Элемент!
оператор возвращался1
С0
и0
от всего остального. Двойной!
был использован для инвертирования тех, и это было там, чтобы убедиться, что значение просто0
или1
в зависимости от логического значение.в C++, с момента введения правильного
bool
тип, там нет необходимости делать это больше. Но вы не можете просто обновить все устаревшие источники, и вы не должны, из-за обратной совместимости с C С C++ (большую часть времени). Но многие люди все еще делают это, по той же причине: чтобы сохранить их код обратно совместимым со старыми компиляторами, которые все еще не понимаютbool
s.и это единственный реальный ответ. Другие ответы вводят в заблуждение.
потому что !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. Целое число может иметь любое состояние от -2147483648 до 2147483647, принимая 32-разрядное целое число со знаком. Унарный ! оператор выводит 1, если вход равен 0, и выводит 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] > _и по крайней мере один человек думает, что если абсолютный новичок не распознает его значение, то это нехорошо. Ну, это глупо. Есть много такого, что абсолютные новички не признают и не понимают. Писать свой код так, чтобы его понимал любой новичок-это не то, что нужно профессионалам. Даже для студентов. Начиная с пути исключения операторов и комбинаций операторов, которые не распознают абсолютные новички... Ну у меня нет слов дайте этому подходу соответствующее описание, извините.
Cheers & hth.,
ответ 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. (Только boolean_converter в MSVC 19 2017 приводит к большему количеству 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
нашел здесь. Это гибкое решение, которое более четко, что он делает и может использоваться следующим образом:bool IsWindow = boolean_cast< bool >(::IsWindow(hWnd));