문제

방금 꽤 큰 코드 기반이있는 프로젝트에 나왔습니다.

나는 주로 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) 어떤 사람들이 부르는 것입니다 더블 뱅 트릭.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top