다음 코드가 표시된 장소에서 경고를 표시하지 않는 이유를 이해하려고합니다.
//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