programing

왜 0 < -0x80000000 인가요?

sourcetip 2022. 7. 14. 23:20
반응형

왜 0 < -0x80000000 인가요?

아래에 간단한 프로그램이 있습니다.

#include <stdio.h>

#define INT32_MIN        (-0x80000000)

int main(void) 
{
    long long bal = 0;

    if(bal < INT32_MIN )
    {
        printf("Failed!!!");
    }
    else
    {
        printf("Success!!!");
    }
    return 0;
}

조건if(bal < INT32_MIN )항상 진실입니다.그게 어떻게 가능해?

매크로를 다음과 같이 변경하면 정상적으로 동작합니다.

#define INT32_MIN        (-2147483648L)

누가 그 문제를 지적할 수 있나요?

이건 좀 미묘하네요.

프로그램의 모든 정수 리터럴에는 유형이 있습니다.6.4.4.1의 표에 의해 규제되는 유형은 무엇입니까?

Suffix      Decimal Constant    Octal or Hexadecimal Constant

none        int                 int
            long int            unsigned int
            long long int       long int
                                unsigned long int
                                long long int
                                unsigned long long int

리터럴 번호가 기본값에 맞지 않는 경우inttype은 위의 표와 같이 다음으로 큰 타입을 시도합니다.따라서 정규 10진 정수 리터럴의 경우 다음과 같습니다.

  • 해라int
  • 안 맞으면 해봐long
  • 안 맞으면 해봐long long.

하지만 16진수는 다르게 행동합니다!리터럴이 부호 있는 글씨체 안에 들어가지 않으면int, 먼저 시도합니다.unsigned int더 큰 활자를 시도하기 전에 말이죠.위 표의 차이를 참조하십시오.

32비트 시스템에서는 리터럴이0x80000000종류unsigned int.

즉, 단항식을 적용할 수 있습니다.-서명된 정수를 오버플로 할 때와는 달리 구현 정의 동작을 호출하지 않고 리터럴에 연산자를 추가합니다.대신, 당신은 그 가치를 얻게 될 것이다.0x80000000, 양의 값.

bal < INT32_MIN일반적인 산술 변환과 식의 결과를 호출한다.0x80000000에서 승격하다unsigned int로.long long. 값0x800000000은 0x80000000보다 작기 때문에 결과는 다음과 같습니다.

리터럴을 다음으로 치환하는 경우2147483648L당신은 10진 표기를 사용하므로 컴파일러는 이 표기를 선택하지 않습니다.unsigned int, 그러나 오히려 그것을 안에 넣으려고 합니다.long또한 L 접미사는 당신이 원한다는 것을 나타냅니다.long 가능하다면요.L 접미사는 실제로 6.4.4.1에 기재된 표를 계속 읽으면 유사한 규칙이 있습니다.요청된 번호에 맞지 않습니다.long32비트 케이스에서는 그렇지 않지만 컴파일러에 의해long long딱 맞는 곳이죠

0x80000000는 입니다.unsigned값이 2147483648인 리터럴.

여기에 단항 마이너스(-)를 적용해도 값이 0이 아닌 부호 없는 유형이 계속 표시됩니다.(실제로 제로 이외의 값일 경우)x최종적으로 얻을 수 있는 가치는 다음과 같습니다.UINT_MAX - x + 1.)

이 정수 리터럴0x80000000타입이 있다unsigned int.

C기준(6.4.4.1 정수)에 의거한다.

5 정수 상수의 유형은 해당 값을 나타낼 수 있는 첫 번째 목록입니다.

그리고 이 정수 상수는 다음과 같은 유형으로 나타낼 수 있다.unsigned int.

그래서 이 표현은

-0x80000000같은 것을 가지다unsigned inttype. 게다가 같은 값을 가지고 있습니다.0x80000000다음 방법으로 계산되는 두 개의 보완 표현에서

-0x80000000 = ~0x80000000 + 1 => 0x7FFFFFFF + 1 => 0x80000000

이것은 예를 들어 글을 쓰면 부작용이 있다.

int x = INT_MIN;
x = abs( x );

결과는 다시 나올 것이다.INT_MIN.

따라서 이 상태에서는

bal < INT32_MIN

비교가 되다0서명되지 않은 가치로0x80000000일반적인 산술 변환 규칙에 따라 long long int로 변환됩니다.

0이 다음보다 작다는 것은 명백합니다.0x80000000.

숫자 상수0x80000000종류unsigned int우리가 가져가면-0x800000002s 칭찬 계산을 하면 다음과 같은 결과가 나옵니다.

~0x80000000 = 0x7FFFFFFF
0x7FFFFFFF + 1 = 0x80000000

그렇게-0x80000000 == 0x80000000그리고 비교.(0 < 0x80000000)(이후로)0x80000000is unsigned)는 참입니다.

생각하기에 혼란스러운 점이 있다.-는 숫자 상수의 일부입니다.

아래 코드0x80000000는 숫자 상수입니다.그것의 종류는 그것만으로 결정됩니다.-나중에 적용되며 유형은 변경되지 않습니다.

#define INT32_MIN        (-0x80000000)
long long bal = 0;
if (bal < INT32_MIN )

꾸미지 않은 원시 숫자 상수는 양수입니다.

10진수일 경우 할당된 유형은 해당 유형을 유지하는 첫 번째 유형입니다.int,long,long long.

정수가 8진수 또는 16진수일 경우 정수를 유지하는 첫 번째 유형을 가져옵니다.int,unsigned,long,unsigned long,long long,unsigned long long.

0x80000000, OP 시스템에서 다음과 같은 유형을 가져옵니다.unsigned또는unsigned long어느 쪽이든 서명되지 않은 유형입니다.

-0x80000000또한 0이 아닌 값이며 부호 없는 유형일 경우 0보다 큽니다.코드와 비교한 경우long long비교의 양면에서 은 변경되지 않습니다.0 < INT32_MIN정말이에요.


대체 정의는 이러한 호기심 동작을 방지합니다.

#define INT32_MIN        (-2147483647 - 1)

잠시 동안 환상의 땅을 걷자int그리고.unsigned48비트입니다.

그리고나서0x80000000에 들어맞다int타입도 그렇고int.-0x80000000음수가 되고 출력 결과가 다릅니다.

[본문으로 돌아가기]

부터0x80000000부호 있는 타입 앞에 있는 부호 없는 타입에 들어맞습니다.그것은 보다 크기 때문입니다.some_signed_MAX아직 안에some_unsigned_MAX부호 없는 타입입니다.

C에는 정수 리터럴이 다음과 같은 규칙이 있습니다.signed또는unsigned에 적합한지에 따라 다르다signed또는unsigned(프로모션)에서32-비트 머신 더 리터럴0x80000000될 것이다unsigned. 2의 보완:-0x800000000x8000000032비트 머신에 접속할 수 있습니다.따라서 비교는bal < INT32_MIN사이에 있다signed그리고.unsignedC 규칙에 따라 비교하기 전에unsigned int로 변환됩니다.long long.

C11: 6.3.1.8/1:

[...] 그렇지 않으면 부호 있는 정수형을 가진 피연산자 유형이 부호 없는 정수형을 가진 피연산자 유형의 모든 값을 나타낼 수 있는 경우 부호 없는 정수형을 가진 피연산자 유형은 부호 있는 정수형을 가진 피연산자 유형으로 변환됩니다.

그러므로,bal < INT32_MIN항상 있다true.

언급URL : https://stackoverflow.com/questions/34182672/why-is-0-0x80000000

반응형