Зачем использовать!! при преобразовании int в bool?
Что может быть причиной преобразования целого числа в логическое значение таким образом?
bool booleanValue = !!integerValue;
вместо
bool booleanValue = integerValue;
Все, что я знаю, это то, что в VС++ 7 последнее вызовет предупреждение C4800, а первое не будет. Есть ли другая разница между ними?
Ответы
Ответ 1
Проблемы с "!!" идиома заключается в том, что она красная, трудно различимая, легко ошибочно принята за опечатку, легко отбросить одну из "!" и т.д. Я помещал его в категорию "посмотрите, как мило, мы можем быть с C/С++".
Просто напишите bool isNonZero = (integerValue != 0);
... ясно.
Ответ 2
Исторически, идиома !!
использовалась для обеспечения того, чтобы ваш bool действительно содержал одно из двух значений, ожидаемых в переменной bool
-like, поскольку C и С++ не имели истинного типа bool
, и мы подделал его с помощью int
s. Это сейчас проблема с "реальным" bool
s.
Но использование !!
является эффективным средством документирования (как для компилятора, так и для любых будущих людей, работающих в вашем коде), что да, вы действительно намеревались использовать этот int
для bool
.
Ответ 3
Потому что! integerValue означает integerValue == 0 и!! integerValue, значит, integerValue!= 0, действительное выражение, возвращающее bool. Последний - это литье с потерей информации.
Ответ 4
Он используется, потому что язык C (и некоторые предварительные стандартные компиляторы С++ тоже) не имел типа bool
, просто int
. Таким образом, int
были использованы для представления логических значений: 0
должен был означать false
, а все остальное было true
. Оператор !
возвращал 1
из 0
и 0
из всего остального. Двойной !
использовался для инвертирования данных, и он должен был убедиться, что это значение равно 0
или 1
в зависимости от его логического значения.
В С++, начиная с введения правильного типа bool
, больше не нужно этого делать. Но вы не можете просто обновлять все устаревшие источники, и вам не придется этого делать из-за обратной совместимости C с С++ (большую часть времени). Но многие люди по-прежнему делают это по той же причине: оставить свой код обратно совместимым со старыми компиляторами, которые до сих пор не понимают bool
s.
И это единственный реальный ответ. Другие ответы вводят в заблуждение.
Ответ 5
Другим вариантом является тернарный оператор, который, как представляется, генерирует одну строку меньше кода сборки (в любом случае в 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
Versus:
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
Я знаю, что это не огромная разница, но мне было любопытно, и я просто подумал, что поделюсь своими выводами.
Ответ 6
Bool может иметь только два состояния: 0 и 1. Целое число может иметь любое состояние от -2147483648 до 2147483647 при условии, что это 32-битное целое число. Унарный! операционные выходы 1, если вход равен 0 и выдает 0, если входной сигнал есть что угодно, кроме 0. Итак! 0 = 1 и! 234 = 0. Второе! просто переключает выход так, что 0 становится 1 и 1 становится 0.
Итак, первое утверждение гарантирует, что booleanValue будет установлено равным либо 0, либо 1, и никаким другим значением, второе утверждение не будет.
Ответ 7
!!
- это идиоматический способ преобразования в bool
, и он работает, чтобы заткнуть компилятор Visual С++ глупого предупреждения о предполагаемой неэффективности такого преобразования.
По другим ответам и комментариям я вижу, что многие люди не знакомы с этой полезностью идиомы в программировании 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]
> _
И по крайней мере один человек думает, что если полный новичок не признает его значение, тогда он не облагорожен. Что ж, это глупо. Там много, что новички не узнают и не понимают. Написание одного кода, чтобы он понимал любой новичок, не для профессионалов. Даже для студентов. Начиная с пути исключения операторов и комбинаций операторов, которые нот-новички не распознают... Ну, у меня нет слов, чтобы дать этому подходу подходящее описание, извините.
Приветствия и hth.,
Ответ 8
Ответ пользователя143506 правильный, но для возможной проблемы с производительностью я сравнил возможности в 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);
}
Ответ 9
Никакая большая причина, кроме параноика или крика через код, что его bool.
для компилятора, в конце концов, он не будет иметь разницы.
Ответ 10
Мне никогда не нравится этот метод преобразования в тип данных bool
- он плохо пахнет!
Вместо этого мы используем удобный шаблон под названием boolean_cast
найденный здесь. Это гибкое решение, более ясное в том, что он делает и может использовать следующее:
bool IsWindow = boolean_cast< bool >(::IsWindow(hWnd));