Зачем использовать! при конвертации int в bool?


что может быть причиной для преобразования целого числа в булево таким образом?

bool booleanValue = !!integerValue;

вместо

bool booleanValue = integerValue;

все, что я знаю, это то, что в VC++7 последнее вызовет C4800 предупреждение а первый не будет. Есть ли еще какая-то разница между ними?

10 75

10 ответов:

проблемы с "!!"идиома заключается в том, что это кратко, трудно увидеть, легко ошибиться для опечатки, легко уронить один из "!'S", и так далее. Я поместил его в категорию" посмотрите, как мило мы можем быть с C/C++".

Просто напишите bool isNonZero = (integerValue != 0); ... быть ясным.

исторически !! идиома была использована для того, чтобы убедиться, что ваш bool действительно содержит одно из двух значений, ожидаемых в bool-как переменная, потому что C и C++ не было true bool тип и мы подделали его с ints. теперь это меньше проблема с "Реалом"bools.

, но через !! является эффективным средством документирования (как для компилятора, так и для любых будущих людей, работающих в вашем коде), что да, вы действительно намеревались бросить это 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));