C ++ 코드의 이중 부정
방금 거대한 코드 기반으로 프로젝트를 시작했습니다.
나는 주로 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가 가지고있는 캐스트-bool에 가장 가깝기 때문입니다.
이 코드는 C ++에서도 사용할 수 있습니다. 가장 일반적인 분모입니다. 가능하면 C와 C ++ 모두에서 작동하는 작업을 수행하십시오.
코더는 피연산자를 bool로 변환한다고 생각하지만 &&의 피연산자는 이미 암시 적으로 bool로 변환되므로 완전히 중복됩니다.
그것은 쓰기를 피하는 기술입니다 (variable! = 0). 즉 어떤 유형에서든지 bool로 변환하는 것입니다.
이와 같은 IMO 코드는 유지 관리가 필요한 시스템에는 자리가 없습니다. 즉, 즉시 읽을 수있는 코드가 아니기 때문입니다 (따라서 첫 번째 질문).
불필요하게 복잡한 것을 이해하려면 시간이 걸리기 때문에 코드는 읽기 쉬워야합니다.
네 맞습니다. 그리고 당신은 무언가를 놓치고 있지 않습니다. !!
bool 로의 변환입니다. 자세한 내용은 이 질문 을 참조하십시오 .
컴파일러 경고를 회피합니다. 이 시도:
int _tmain(int argc, _TCHAR* argv[])
{
int foo = 5;
bool bar = foo;
bool baz = !!foo;
return 0;
}
'bar'줄은 MSVC ++에서 "강제 값을 'true'또는 'false'(성능 경고)로 생성하지만 'baz'줄은 미세하게 몰래 들어옵니다.
운영자입니다! 과부하?
그렇지 않으면 아마도 경고를하지 않고 변수를 부울로 변환하기 위해이 작업을 수행하고있을 것입니다. 이것은 분명히 표준 작업 방식이 아닙니다.
레거시 C 개발자들은 종종 있으므로, 어떤 부울 유형을 없었다 #define TRUE 1
및 #define FALSE 0
다음 부울 비교를 임의의 숫자 데이터 유형을 사용했다. 이제 우리는 bool
, 숫자 유형과 부울 유형의 혼합을 사용하여 특정 유형의 할당 및 비교가 수행되면 많은 컴파일러가 경고를 표시합니다. 이 두 가지 사용법은 레거시 코드로 작업 할 때 충돌합니다.
이 문제를 해결하기 위해 일부 개발자는 다음 부울 ID를 사용합니다. !num_value
returns bool true
if num_value == 0
; false
그렇지 않으면. !!num_value
반환 bool false
하는 경우 num_value == 0
; true
그렇지 않으면. 단일 부정은로 변환 num_value
하기에 충분 합니다 bool
. 그러나 부울 표현식의 원래 의미를 복원하려면 이중 부정이 필요합니다.
이 패턴은 관용구 , 즉 언어에 익숙한 사람들이 일반적으로 사용 하는 것으로 알려져 있습니다. 따라서 나는 그것을 원하는만큼 반 패턴으로 보지 않는다 static_cast<bool>(num_value)
. 캐스트는 올바른 결과를 제공 할 수 있지만 일부 컴파일러는 성능 경고를 표시하므로 여전히 해결해야합니다.
이 문제를 해결하는 다른 방법은 (num_value != FALSE)
. 나는 그것도 괜찮지 만, 전체적으로 !!num_value
훨씬 덜 장황하고, 더 명확하고, 두 번째로 볼 때 혼란스럽지 않습니다.
으로 마르신가 언급 한 연산자 오버로딩 플레이에있는 경우, 그것은 또한 문제가 있습니다. 그렇지 않으면 C / C ++에서는 다음 중 하나를 수행하는 경우를 제외하고는 중요하지 않습니다.
직접 비교
true
(또는 C와 같은TRUE
매크로)는 거의 항상 나쁜 생각입니다. 예를 들면 다음과 같습니다.if (api.lookup("some-string") == true) {...}
당신은 단순히 엄격한 0/1 값으로 변환 된 것을 원합니다. C ++에서
bool
의지에 대한 할당 은 암시 적으로 이것을 수행합니다 (암시 적으로으로 변환 할 수있는 것들bool
). C 또는 bool이 아닌 변수를 다루는 경우 이것은 내가 본 관용구이지만(some_variable != 0)
다양성을 선호합니다 .
더 큰 부울 식의 맥락에서 그것은 단순히 물건을 복잡하게 만든다고 생각합니다.
경우 변수가 객체 유형이다, 그것은있을 수 있습니다! 연산자가 정의되었지만 부울로 캐스트되지 않음 (또는 다른 의미로 int 로의 암시 적 캐스트가 더 나쁩니다. 연산자를 두 번 호출하면 이상한 경우에도 작동하는 부울로 변환됩니다.
!!
부울 유형이없는 원래 C ++에 대처하는 데 사용되었습니다 (C와 같지 않음).
문제 예 :
Inside if(condition)
, the condition
needs to evaluate to some type like double, int, void*
, etc., but not bool
as it does not exist yet.
Say a class existed int256
(a 256 bit integer) and all integer conversions/casts were overloaded.
int256 x = foo();
if (x) ...
To test if x
was "true" or non-zero, if (x)
would convert x
to some integer and then assess if that int
was non-zero. A typical overload of (int) x
would return only the LSbits of x
. if (x)
was then only testing the LSbits of x
.
But C++ has the !
operator. An overloaded !x
would typically evaluate all the bits of x
. So to get back to the non-inverted logic if (!!x)
is used.
It's correct but, in C, pointless here -- 'if' and '&&' would treat the expression the same way without the '!!'.
The reason to do this in C++, I suppose, is that '&&' could be overloaded. But then, so could '!', so it doesn't really guarantee you get a bool, without looking at the code for the types of variable
and api.call
. Maybe someone with more C++ experience could explain; perhaps it's meant as a defense-in-depth sort of measure, not a guarantee.
Maybe the programmers were thinking something like this...
!!myAnswer is boolean. In context, it should become boolean, but I just love to bang bang things to make sure, because once upon a time there was a mysterious bug that bit me, and bang bang, I killed it.
This may be an example of the double-bang trick, see The Safe Bool Idiom for more details. Here I summarize the first page of the article.
In C++ there are a number of ways to provide Boolean tests for classes.
An obvious way is
operator bool
conversion operator.
// operator bool version
class Testable {
bool ok_;
public:
explicit Testable(bool b=true):ok_(b) {}
operator bool() const { // use bool conversion operator
return ok_;
}
};
We can test the class,
Testable test;
if (test)
std::cout << "Yes, test is working!\n";
else
std::cout << "No, test is not working!\n";
However, opereator bool
is considered unsafe because it allows nonsensical operations such as test << 1;
or int i=test
.
Using
operator!
is safer because we avoid implicit conversion or overloading issues.
The implementation is trivial,
bool operator!() const { // use operator!
return !ok_;
}
The two idiomatic ways to test Testable
object are
Testable test;
if (!!test)
std::cout << "Yes, test is working!\n";
if (!test2) {
std::cout << "No, test2 is not working!\n";
The first version if (!!test)
is what some people call the double-bang trick.
참고URL : https://stackoverflow.com/questions/248693/double-negation-in-c-code
'IT박스' 카테고리의 다른 글
기다리는 Thread.Sleep를 얻는 방법? (0) | 2020.07.19 |
---|---|
제출 버튼없이 Enter 키를 사용하여 양식을 제출 하시겠습니까? (0) | 2020.07.19 |
IE8에서 addEventListener가 작동하지 않음 (0) | 2020.07.19 |
집계 함수가없는 TSQL 피벗 (0) | 2020.07.19 |
Mac OS의 IntelliJ IDEA JDK 구성 (0) | 2020.07.19 |