문제
방금 꽤 큰 코드 기반이있는 프로젝트에 나왔습니다.
나는 주로 C ++를 다루고 있으며 그들이 쓰는 많은 코드는 부울 논리에 이중 부정을 사용합니다.
if (!!variable && (!!api.lookup("some-string"))) {
do_some_stuff();
}
나는이 사람들이 지능적인 프로그래머라는 것을 알고 있습니다. 우연히이 일을하지 않는 것은 분명합니다.
나는 노련한 C ++ 전문가가 아닙니다. 그들이 왜 그렇게하고 있는지에 대한 나의 유일한 추측은 그들이 평가되는 가치가 실제 부울 표현이라는 것을 절대적으로 긍정적으로 만들고 싶어한다는 것입니다. 그래서 그들은 그것을 부정 한 다음 다시 그것을 부정하여 실제 부울 가치로 되돌려 놓습니다.
이것은 정확합니까, 아니면 내가 뭔가를 놓치고 있습니까?
해결책
Bool로 변환하는 것은 트릭입니다.
다른 팁
실제로 어떤 상황에서는 매우 유용한 관용구입니다. 이 매크로를 가져 가십시오 (Linux 커널의 예). GCC의 경우 다음과 같이 구현됩니다.
#define likely(cond) (__builtin_expect(!!(cond), 1))
#define unlikely(cond) (__builtin_expect(!!(cond), 0))
왜 그들은 이것을해야합니까? GCC __builtin_expect
매개 변수를 다음과 같이 처리합니다 long
그리고 아닙니다 bool
, 어떤 형태의 전환이 필요합니다. 그들은 무엇을 모르기 때문에 cond
그들이 그 매크로를 쓸 때 단순히 사용하는 것이 가장 일반적입니다. !!
관용구.
그들은 아마도 0과 비교하여 똑같은 일을 할 수 있지만, 제 생각에는 C가 가지고있는 캐스트 투-울에 가장 가깝기 때문에 이중 분석을하는 것이 실제로 더 간단합니다.
이 코드는 C ++에서도 사용될 수 있습니다 ... 가장 낮은 공통 노미네이터입니다. 가능하면 C와 C ++에서 작동하는 작업을 수행하십시오.
코더는 피연산자를 bool로 변환 할 것이라고 생각하지만 &&의 피연산자는 이미 암시 적으로 bool로 변환되기 때문에 완전히 중복됩니다.
예, 맞습니다. 아니요, 당신은 무언가를 놓치지 않습니다. !!
Bool 로의 전환입니다. 보다 이 질문 더 많은 토론을 위해.
글쓰기를 피하는 기술입니다 (변수! = 0) - 즉 부울으로 변환하는 것이 좋습니다.
이와 같은 IMO 코드는 유지해야 할 시스템에서 자리를 차지할 수 없습니다. 즉시 읽을 수없는 코드가 아니기 때문에 (따라서 처음에는 질문).
코드는 읽을 수 있어야합니다. 그렇지 않으면 불필요하게 복잡한 것을 이해하는 데 시간이 걸리므로 미래에 대한 부채 유산을 남깁니다.
컴파일러 경고가 측면입니다. 이 시도:
int _tmain(int argc, _TCHAR* argv[])
{
int foo = 5;
bool bar = foo;
bool baz = !!foo;
return 0;
}
'Bar'라인은 MSVC ++에서 "BOOL 'True'또는 'False'(성능 경고)를 강제로 생성하지만 'BAZ'라인은 잘 몰래 들어옵니다.
운영자입니다! 과부하?
그렇지 않다면, 그들은 경고를 생성하지 않고 변수를 부울로 변환하기 위해 이것을하고있을 것입니다. 이것은 확실히 일을하는 표준 방법이 아닙니다.
레거시 C 개발자는 부울 유형이 없었기 때문에 종종 #define TRUE 1
그리고 #define FALSE 0
그런 다음 부울 비교를 위해 임의의 숫자 데이터 유형을 사용했습니다. 이제 우리는 가지고 있습니다 bool
, 많은 컴파일러는 숫자 유형과 부울 유형의 혼합을 사용하여 특정 유형의 할당과 비교가 이루어질 때 경고를 방출합니다. 이 두 가지 사용법은 레거시 코드로 작업 할 때 결국 충돌합니다.
이 문제를 해결하기 위해 일부 개발자는 다음 부울 정체성을 사용합니다. !num_value
보고 bool true
만약에 num_value == 0
; false
그렇지 않으면. !!num_value
보고 bool false
만약에 num_value == 0
; true
그렇지 않으면. 단일 부정은 변환하기에 충분합니다 num_value
에게 bool
; 그러나 부울 표현의 원래 의미를 회복하려면 이중 부정이 필요합니다.
이 패턴은 an이라고합니다 관용구, 즉, 언어에 익숙한 사람들이 일반적으로 사용하는 것. 그러므로 나는 그것을 나와 마찬가지 static_cast<bool>(num_value)
. 캐스트는 올바른 결과를 제공 할 수 있지만 일부 컴파일러는 성능 경고를 방출하므로 여전히이를 해결해야합니다.
이것을 해결하는 다른 방법은 말하는 것입니다. (num_value != FALSE)
. 나도 괜찮아요. !!num_value
오진이 훨씬 적고 명확 할 수 있으며, 두 번째로 볼 때 혼란스럽지 않습니다.
처럼 Marcin 언급하면, 운영자 과부하가 진행 중인지 여부는 중요 할 수 있습니다. 그렇지 않으면 C/C ++에서 다음 중 하나를 수행하는 경우를 제외하고는 중요하지 않습니다.
직접 비교
true
(또는 C에서 a와 같은 것TRUE
매크로), 거의 항상 나쁜 생각입니다. 예를 들어:if (api.lookup("some-string") == true) {...}
당신은 단순히 무언가를 엄격한 0/1 값으로 변환하기를 원합니다. C ++에서 A에 대한 할당
bool
이를 암시 적으로 수행합니다 (암시 적으로 변환 가능한 것들에 대해bool
). C에서 또는 당신이 비 지구 변수를 다루고 있다면, 이것은 내가 본 관용구이지만 나는 선호합니다.(some_variable != 0)
나 자신.
나는 더 큰 부울 표현의 맥락에서 단순히 물건을 막는다 고 생각합니다.
만약에 변하기 쉬운 객체 유형이고 가질 수 있습니다! 운영자는 부울에 대한 캐스트가 없었지만 (또는 다른 의미론으로 int에 대한 암시 적 캐스트가 나쁘다.! 운영자를 두 번 부르면 이상한 경우에도 작동하는 bool로 변환됩니다.
!!
부울 유형이없는 원래 C ++에 대처하는 데 사용되었습니다 (c도 마찬가지).
예제 문제 :
내부에 if(condition)
,, condition
같은 유형으로 평가해야합니다 double, int, void*
, 등이지만 그렇지 않습니다 bool
아직 존재하지 않기 때문에.
수업이 존재한다고 말하십시오 int256
(256 비트 정수) 및 모든 정수 변환/캐스트가 과부하되었습니다.
int256 x = foo();
if (x) ...
테스트하려면 x
"참"이거나 0이 아니 었습니다. if (x)
변환 할 것입니다 x
정수와 그 다음에 그 경우 평가하십시오 int
0이 아니었다. 일반적인 과부하 (int) x
LSBITS 만 반환합니다 x
. if (x)
그런 다음 lsbits 만 테스트했습니다 x
.
그러나 C ++는 다음과 같습니다 !
운영자. 과부하 !x
일반적으로 모든 비트를 평가합니다 x
. 따라서 비 반전 논리로 돌아갑니다 if (!!x)
사용.
심판 C ++의 이전 버전이`if ()`문서에서 조건을 평가할 때 클래스의 'int` 연산자를 사용 했습니까?
맞습니다. C에서는 여기에서 무의미합니다 - 'if'및 '&&'는 '!!'없이 표현을 같은 방식으로 취급합니다.
C ++ 에서이 작업을 수행 해야하는 이유는 '&&'가 과부하 될 수 있기 때문입니다. 하지만 그렇다면 '!'도 마찬가지입니다. 진짜 유형의 코드를 보지 않고 부를 얻을 수 있습니다. variable
그리고 api.call
. 더 많은 C ++ 경험을 가진 사람이 설명 할 수있을 것입니다. 아마도 그것은 보장이 아니라 깊은 방어의 일종의 측정을 의미 할 것입니다.
아마도 프로그래머들이 이런 생각을하고 있었을 것입니다 ...
!! myanswer는 부울입니다. 맥락에서, 그것은 부울이되어야하지만, 나는 단지 한 번에 나를 물고 Bang Bang이있는 신비한 벌레가 있었기 때문에 나는 그것을 죽였기 때문에 나는 단지 물건을 강타하는 것을 좋아한다.
이것은 예의 예일 수 있습니다 더블 뱅 트릭, 보다 안전한 부리 관용구 자세한 사항은. 여기서 나는 기사의 첫 페이지를 요약합니다.
C ++에는 수업에 부울 테스트를 제공하는 여러 가지 방법이 있습니다.
명백한 방법은
operator bool
변환 연산자.
// operator bool version
class Testable {
bool ok_;
public:
explicit Testable(bool b=true):ok_(b) {}
operator bool() const { // use bool conversion operator
return ok_;
}
};
우리는 수업을 테스트 할 수 있습니다.
Testable test;
if (test)
std::cout << "Yes, test is working!\n";
else
std::cout << "No, test is not working!\n";
하지만, opereator bool
다음과 같은 무의미한 작업을 허용하기 때문에 안전하지 않은 것으로 간주됩니다. test << 1;
또는 int i=test
.
사용
operator!
암시 적 변환 또는 과부하 문제를 피하기 때문에 더 안전합니다.
구현은 사소하고
bool operator!() const { // use operator!
return !ok_;
}
두 가지 관용적 인 테스트 방법 Testable
대상은
Testable test;
if (!!test)
std::cout << "Yes, test is working!\n";
if (!test2) {
std::cout << "No, test2 is not working!\n";
첫 번째 버전 if (!!test)
어떤 사람들이 부르는 것입니다 더블 뱅 트릭.