C ++에서 (-2147483648> 0)이 true를 반환합니까?


241

-2147483648은 32 비트 정수 유형의 가장 작은 정수이지만 if(...)문장 에서 오버플로되는 것처럼 보입니다 .

if (-2147483648 > 0)
    std::cout << "true";
else
    std::cout << "false";

이것은 true내 테스트에서 인쇄 됩니다. 그러나 -2147483648을 정수로 캐스트하면 결과가 달라집니다.

if (int(-2147483648) > 0)
    std::cout << "true";
else
    std::cout << "false";

인쇄 false됩니다.

혼란 스러워요. 누구든지 이것에 대해 설명 할 수 있습니까?


02-05-2012 업데이트 :

귀하의 의견에 감사드립니다. 내 컴파일러에서 int의 크기는 4 바이트입니다. 간단한 테스트를 위해 VC를 사용하고 있습니다. 내 질문의 설명을 변경했습니다.

이 글에서 AndreyT 는 컴파일러가 그러한 입력에서 동작하는 방법과이 최소 정수가 어떻게 구현되었는지에 대해 매우 자세하게 설명했습니다. 반면qPCR4vir 는 관련된 "호기심"과 정수 표현 방법을 제시했습니다. 너무 인상적입니다!


48
"우리는 모두 -2147483648이 가장 작은 정수의 수라는 것을 알고 있습니다" 이것은 정수 의 크기에 따라 다릅니다.
orlp

14
"우리는 모두 -2147483648이 가장 적은 정수라는 것을 알고 있습니다"-나는 그들 중 무한히 많은 수가 있기 때문에 가장 작은 정수는 없다고 생각했습니다.

@Inisheer 4 바이트 정수 당신이 가질 수 INT_MIN의를 -9223372036854775808하는 경우, CHAR_BIT16 그리고도 함께 CHAR_BIT == 8하고 sizeof(int== 4)`당신이 얻을 수 있습니다 -9223372036854775807C 2-보완 번호를 필요로하지 않기 때문에.
12431234123412341234123

답변:


391

-2147483648"숫자"가 아닙니다. C ++ 언어는 음수 리터럴 값을 지원하지 않습니다.

-2147483648실제로는 표현식입니다. 앞에 2147483648단항 -연산자가 있는 양수 리터럴 값 입니다 . 플랫폼 2147483648에서 긍정적 인 int범위에 비해 값 이 너무 큽니다 . 유형 long int이 플랫폼에서 더 큰 범위를 가지면 컴파일러 2147483648long int유형 이 있다고 가정해야 합니다. (C ++ 11에서 컴파일러는 long long int유형 도 고려해야 합니다.) 이렇게하면 컴파일러가 -2147483648더 큰 유형의 도메인에서 평가하게 되므로 결과는 부정적입니다.

그러나 분명히 귀하의 경우 범위는의 범위 long int와 동일하며 int일반적으로 int플랫폼 보다 범위가 큰 정수 유형이 없습니다 . 이것은 공식적으로 양의 상수가 2147483648사용 가능한 모든 부호있는 정수 유형을 오버플로한다는 것을 의미하며, 이는 프로그램의 동작이 정의되지 않았 음을 의미합니다. (언어 사양이 진단 메시지를 요구하는 대신 정의되지 않은 동작을 선택한다는 것은 약간 이상하지만, 그 방법이 맞습니다.)

실제로, 행동이 정의되지 않았다는 점을 고려하면, 2147483648단항을 -적용한 후에는 긍정적으로 변하는 구현에 따른 부정적인 값으로 해석 될 수 있습니다. 또는 일부 구현에서는 값을 나타 내기 위해 부호없는 유형을 사용하려고 시도 할 수 있습니다 (예 : C89 / 90 컴파일러 unsigned long int에서는 C99 또는 C ++에서는 사용 하지 않아야 함). 어쨌든 동작이 정의되어 있지 않기 때문에 구현은 무엇이든 할 수 있습니다.

참고로, 이것이 상수 INT_MIN가 일반적으로 다음과 같이 정의되는 이유입니다.

#define INT_MIN (-2147483647 - 1)

더 직설적으로 보이는 대신

#define INT_MIN -2147483648

후자는 의도 한대로 작동하지 않습니다.


78
이것이 또한 이렇게하는 이유입니다 : #define INT_MIN (-2147483647 - 1).
orlp

5
@ RichardJ.RossIII-clang을 사용하면 64 비트 형식의 리터럴을 얻을 수 int있습니다. OP의 구현에는 64 비트 유형이 없을 수 있습니다.
칼 노룸

1
@ RichardJ.RossIII : 나는이 동작이 구현 정의 / 정의되지 않았다고 생각합니다.
Oliver Charlesworth

3
나는 "음수"가 그렇게 해석되지 않는다고 생각하지 않았다. 이유가 보이지 않습니다. 나는 -1.0그것이 음의 이중 값으로 해석 되기를 바랍니다 .
leemes 2019

6
@ qPCR4vir : 아니요. 귀하의 답변에 대한 의견에 썼 듯이 현대 C 또는 C ++에서는이 경우 부호없는 유형을 사용할 수 없습니다 ( 접미사가없는 10 진수 상수 ). unsigned long int이 문맥에서 첫 번째 표준 C (C89 / 90) 만 허용 되었지만 C99에서는이 권한이 제거되었습니다. C 및 C ++에서 접미사가없는 리터럴에는 부호있는 유형 이 있어야합니다 . 서명 된 유형이 작동 할 때 서명되지 않은 유형이 표시되면 컴파일러가 손상되었음을 의미합니다. 서명 된 유형이 작동하지 않을 때 여기에 서명되지 않은 유형이 표시되면 이는 정의되지 않은 동작의 특정 표시 일뿐입니다.
AnT

43

컴파일러 (VC2012)는 값을 보유 할 수있는 "최소"정수로 승격합니다. 첫 번째 경우, signed int(그리고 long int)는 (부호가 적용되기 전에) 수는 없지만, unsigned int할 수 있습니다 2147483648있다unsigned int ???? 유형. 두 번째에서는 강제 int으로부터 unsigned.

const bool i= (-2147483648 > 0) ;  //   --> true

경고 C4146 : 부호없는 유형에 단항 빼기 연산자 적용 , 결과는 여전히 부호 없음

관련 "호기심"은 다음과 같습니다.

const bool b= (-2147483647      > 0) ; //  false
const bool i= (-2147483648      > 0) ; //  true : result still unsigned
const bool c= ( INT_MIN-1       > 0) ; //  true :'-' int constant overflow
const bool f= ( 2147483647      > 0) ; //  true
const bool g= ( 2147483648      > 0) ; //  true
const bool d= ( INT_MAX+1       > 0) ; //  false:'+' int constant overflow
const bool j= ( int(-2147483648)> 0) ; //  false : 
const bool h= ( int(2147483648) > 0) ; //  false
const bool m= (-2147483648L     > 0) ; //  true 
const bool o= (-2147483648LL    > 0) ; //  false

C ++ 11 표준 :

2.14.2 정수 리터럴 [lex.icon]

정수 리터럴은 마침표 나 지수 부분이없는 일련의 숫자입니다. 정수 리터럴에는 기본을 지정하는 접 두부와 유형을 지정하는 접미 부가있을 수 있습니다.

정수 리터럴의 유형은 해당 값을 표시 할 수있는 해당 목록 중 첫 번째입니다.

여기에 이미지 설명을 입력하십시오

정수 리터럴을 목록에서 어떤 유형으로도 표현할 수없고 확장 정수 유형 (3.9.1)이 해당 값을 나타낼 수 있으면 해당 확장 정수 유형을 가질 수 있습니다. 리터럴에 대한 목록의 모든 유형이 서명 된 경우 확장 정수 유형이 서명됩니다. 리터럴에 대한 목록의 모든 유형이 부호가없는 경우 확장 정수 유형은 부호가 없습니다. 목록에 부호있는 유형과 부호없는 유형이 모두 있으면 확장 정수 유형에 부호가 있거나 부호가 없을 수 있습니다. 변환 단위 중 하나에 허용 된 유형으로 표현할 수없는 정수 리터럴이 포함 된 경우 프로그램이 잘못 구성됩니다.

그리고 이것은 표준의 정수에 대한 승격 규칙입니다.

4.5 통합 프로모션 [conv.prom]

이외 정수형의 prvalue bool, char16_t, char32_t, 또는 wchar_t그 정수 변환 계수 (4.13) 이하 INT의 랭크를 초과 유형의 prvalue로 전환 될 수 int있는 경우 int, 소스 타입의 모든 값을 나타낼 수있다; 그렇지 않으면 소스 prvalue를 유형의 prvalue로 변환 할 수 있습니다 unsigned int.


3
qPCR4vir @ :에서 C89 / 90 컴파일러는 사용 유형에 가정 된 int, long int, unsigned long intunsuffixed 소수점 상수를 나타냅니다. 접미사가없는 10 진 상수에 부호없는 유형을 사용할 수있는 유일한 언어였습니다. C ++ 98에서는 int또는 long int입니다. 서명되지 않은 유형은 허용되지 않습니다. C (C99에서 시작) 나 C ++ 모두 컴파일러가이 컨텍스트에서 부호없는 유형을 사용할 수 없습니다. 물론 컴파일러는 서명 된 형식 중 어느 것도 작동하지 않으면 서명되지 않은 형식을 자유롭게 사용할 수 있지만 여전히 정의되지 않은 동작의 특정 표시 일뿐입니다.
AnT

@AndreyT. 큰! couse, 당신의 장비. VC2012가 고장 났습니까?
qPCR4vir

qPCR4vir @ : AFAIK가 사용 중 가지고있는 수단, VC2012는 C ++ 컴파일러 11 아직 없다 (이것은 있습니까?) int또는 long int나타내는데 2147483648. 또한 AFAIK에서 VC2012 모두 intlong int32 비트 유형이다. 이것은 VC2012 리터럴 2147483648에서 정의되지 않은 동작으로 이어져야 함을 의미합니다 . 비헤이비어가 정의되지 않은 경우 컴파일러는 모든 작업을 수행 할 수 있습니다. VC2012가 고장 나지 않았 음을 의미합니다. 단순히 잘못된 진단 메시지를 발행했습니다. 동작이 정의되어 있지 않다는 것을 알리는 대신 서명되지 않은 유형을 사용하기로 결정했습니다.
AnT

@AndreyT : 소스 코드에 부호없는 최대 값을 초과하는 부호없는 10 진수 리터럴이 포함되어 long진단 프로그램을 발행 할 필요가없는 경우 컴파일러에서 코 악마를 자유롭게 방출 할 수 있습니까? 깨진 것 같습니다.
supercat

같은 ++ G에서 "이 소수점 상수는 ISO C90에 서명되지"VS2008에서 "C4146 경고"와
스파이더

6

요컨대,으로 2147483648오버플로 -2147483648하고 (-(-2147483648) > 0)is true입니다.

이것은2147483648 바이너리에서 어떻게 생겼는지입니다.

또한 부호있는 이진 계산의 경우 최상위 비트 ( "MSB")는 부호 비트입니다. 이 질문 은 이유를 설명하는 데 도움 될 수 있습니다.


4

때문에 -2147483648실제로 2147483648부정과 ( -)에 적용된 숫자는 당신이 기대되지 않는 것. 실제로이 의사 코드와 같습니다.operator -(2147483648)

지금, 당신의 컴파일러를 가정하는 것은이 sizeof(int)동일 4CHAR_BIT같이 정의된다 8즉 만들 것, 2147483648정수의 최대 부호있는 값을 오버 플로우 ( 2147483647). 최대 + 1은 무엇입니까? 4 비트, 2s 칭찬 정수로이를 해결할 수 있습니다.

기다림! 8은 정수를 오버플로합니다! 우리는 무엇을해야합니까? 1000비트 의 부호없는 표현을 사용하고 비트를 부호있는 정수로 해석하십시오. 이 표현은 우리 가 모두 알고 있듯이 -82s 보수 부정을 적용하여 8우리보다 큽니다 0.

이것은 왜 <limits.h>(와 <climits>) 일반적 정의 INT_MIN((-2147483647) - 1)- 최대 부호있는 정수가 (그래서 0x7FFFFFFF) (부정한다 0x80000001), 다음 감소 ( 0x80000000).


4 비트 숫자의 경우 2의 보수 부정 -8은 여전히 -8입니다.
벤 Voigt

-8은 음수가 아닌 0-8로 해석됩니다. 8은 4 비트 부호있는 정수를 오버플로합니다.
Cole Johnson

-(8)C ++에서 다음과 같은 것을 고려하십시오 -8-부정 리터럴이 아닌 리터럴에 부정이 적용됩니다. 리터럴은 8부호있는 4 비트 정수에 맞지 않으므로 부호가 없어야합니다. 패턴은 1000입니다. 지금까지 당신의 대답은 정확합니다. 10004 비트에서 2의 보수 부정은 이다 1000. 부호가 있거나 부호가없는 것은 중요하지 않다. 당신의 대답은 "비트를 부호있는 정수로 해석합니다"라고 말합니다. 이것은 -8부정 이전과 마찬가지로 2의 보수 부정 이후의 값을 만듭니다 .
벤 Voigt

물론 "4 비트 C ++"에는 "비트를 부호있는 정수 단계로 해석"이 없습니다. 리터럴은이를 표현할 수있는 가장 작은 유형으로, 부호없는 4 비트 정수 입니다. 리터럴의 값은입니다 8. 부정이 적용되고 (모듈로 16) 최종 결과는입니다 8. 인코딩은 여전히 ​​1000이지만 부호없는 유형이 선택되었으므로 값이 다릅니다.
벤 Voigt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.