부호있는 / 부호없는 비교 // warning C4018: ‘<‘

다음 코드가 표시된 장소에서 경고를 표시하지 않는 이유를 이해하려고합니다.

//from limits.h
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
#define INT_MAX  2147483647 /* maximum (signed) int value */
            /* = 0x7fffffff */

int a = INT_MAX;
//_int64 a = INT_MAX; // makes all warnings go away
unsigned int b = UINT_MAX;
bool c = false;

if(a < b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a > b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a <= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a >= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a == b) // no warning <--- warning expected here
    c = true;
if(((unsigned int)a) == b) // no warning (as expected)
    c = true;
if(a == ((int)b)) // no warning (as expected)
    c = true;

배경 프로모션과 관련이 있다고 생각했는데 마지막 두 사람은 그렇지 않은 것 같습니다.

내 생각에, 첫 번째 ==비교는 다른 것만 큼 서명 / 부호없는 불일치입니까?



답변

부호있는 값과 부호없는 값을 비교할 때 컴파일러는 부호있는 값을 부호없는 값으로 변환합니다. 평등을 위해 이것은 중요하지 않습니다 -1 == (unsigned) -1. 다른 비교의 경우 중요합니다. 예를 들어 다음이 참 -1 > 2U입니다..

편집 : 참조 :

5/9 : (표현식)

산술 또는 열거 유형의 피연산자를 예상하는 많은 이항 연산자는 유사한 방식으로 변환을 일으키고 결과 유형을 산출합니다. 목적은 결과의 유형이기도 한 공통 유형을 생성하는 것입니다. 이 패턴을 일반적인 산술 변환이라고하며 다음과 같이 정의됩니다.

  • 피연산자가 long double 유형이면 다른 피연산자는 long double로 변환됩니다.

  • 그렇지 않으면 피연산자가 double이면 다른 피연산자는 double로 변환됩니다.

  • 그렇지 않으면 피연산자가 float이면 다른 피연산자는 float로 변환됩니다.

  • 그렇지 않으면 적분 프로모션 (4.5)이 두 피연산자 모두에서 수행됩니다 .54)

  • 그런 다음 피연산자가 unsigned long이면 다른 피연산자는 unsigned long으로 변환됩니다.

  • 그렇지 않고 한 피연산자가 long int이고 다른 하나는 unsigned int이면 long int가 unsigned int의 모든 값을 나타낼 수 있으면 unsigned int는 long int로 변환됩니다. 그렇지 않으면 두 피연산자가 unsigned long int로 변환됩니다.

  • 그렇지 않으면 피연산자가 길면 다른 피연산자가 long으로 변환됩니다.

  • 그렇지 않으면 피연산자가 부호가없는 경우 다른 피연산자가 부호없는 것으로 변환됩니다.

4.7 / 2 : (통합 변환)

대상 유형이 부호없는 경우 결과 값은 소스 정수에 합동하는 최소 부호없는 정수입니다 (모듈로 2 n 여기서 n은 부호없는 유형을 나타내는 데 사용되는 비트 수). [참고 : 2의 보수 표현에서이 변환은 개념적이며 비트 패턴에 변화가 없습니다 (잘림이없는 경우). ]

EDIT2 : MSVC 경고 수준

MSVC의 다양한 경고 수준에 대해 경고되는 것은 물론 개발자가 선택한 것입니다. 내가보기에, 부호있는 / 부호없는 평등과 크거나 작은 비교와 관련된 선택이 의미가 있습니다. 이것은 물론 전적으로 주관적입니다.

-1 == -1의미는 다음과 같습니다 -1 == (unsigned) -1. 직관적 인 결과입니다.

-1 < 2 하지 않는 것과 같은 뜻 -1 < (unsigned) 2이 먼저 눈에 덜 직관적이며, IMO에 “이전”경고를받을 자격 -.


답변

서명 된 / 서명되지 않은 경고가 중요하고 프로그래머가주의를 기울여야하는 이유는 다음 예제에서 설명합니다.

이 코드의 출력이 맞습니까?

#include <iostream>

int main() {
        int i = -1;
        unsigned int j = 1;
        if ( i < j )
            std::cout << " i is less than j";
        else
            std::cout << " i is greater than j";

        return 0;
}

산출:

i is greater than j

놀랐나요? 온라인 데모 : http://www.ideone.com/5iCxY

결론 : 비교해 보면 한 피연산자가 unsigned이면 다른 피연산자는 해당 유형이 부호 unsigned 있으면 암시 적으로 변환됩니다 !


답변

== 연산자는 비트 비교를 수행합니다 (단순 나눗셈으로 0인지 확인).

비교보다 작거나 큰 것은 숫자의 부호에 훨씬 더 많이 의존합니다.

4 비트 예 :

1111 = 15? 또는 -1?

그래서 만약 당신이 1111 <0001 … 그것은 모호합니다 …

하지만 만약 당신이 1111 == 1111을 가지고 있다면 … 그것은 당신이 그것을 의미하지는 않았지만 같은 것입니다.


답변

2- 보체 (최신 프로세서)를 사용하여 값을 나타내는 시스템에서는 이진 형식에서도 동일합니다. 이것이 컴파일러가 a == b 에 대해 불평하지 않는 이유 일 수 있습니다 .

그리고 나에게는 이상한 컴파일러가 a == ((int) b) 에 대해 경고하지 않습니다 . 정수 잘림 경고 또는 무언가를 제공해야한다고 생각합니다.


답변

Microsoft 가이 경우를 처리하기 위해 다른 경고 번호 (예 : C4389 )를 사용했고 C4389는 기본적으로 (즉, 수준 3) 활성화되지 않았기 때문에 문제의 코드 줄은 C4018 경고를 생성하지 않습니다 .

C4389에 대한 Microsoft 문서 에서 :

// C4389.cpp
// compile with: /W4
#pragma warning(default: 4389)

int main()
{
   int a = 9;
   unsigned int b = 10;
   if (a == b)   // C4389
      return 0;
   else
      return 0;
};

다른 답변은 Microsoft가 항등 연산자에서 특별한 경우를 만들기로 결정한 이유를 잘 설명했지만 C4389 또는 Visual Studio에서 활성화하는 방법을 언급하지 않고는 그 답변이별로 도움이되지 않는다는 것을 알았 습니다 .

또한 C4389를 활성화하려는 경우 C4388 활성화를 고려할 수도 있습니다. 불행히도 C4388에 대한 공식 문서는 없지만 다음과 같은 표현으로 팝업되는 것 같습니다.

int a = 9;
unsigned int b = 10;
bool equal = (a == b); // C4388