32비트 시스템에서 -(-2147483648) = - 2147483648이 되는 이유는 무엇입니까?
그 질문은 자명하다고 생각합니다만, 아마 오버플로와 관계가 있을 것이라고 생각합니다만, 아직 잘 모르겠습니다.도대체 무슨 일이 벌어지고 있는 거야?
?는 왜?-(-2147483648) = -2147483648
(「C」)
4비트 숫자로 계산해볼게요. 하지만 그 생각은 똑같아요.
4비트 수치로 지정할 수 있는 값은 0000 ~1111 입니다.이는 0 ~ 15이지만 음수를 나타낼 경우 첫 번째 비트가 부호(0은 양수, 1은 음수)를 나타내기 위해 사용됩니다.
그래서 1111은 15가 아니다.첫 번째 비트가 1이기 때문에 음수입니다.그 값을 알기 위해 이전 답변에서 설명한 바와 같이 "비트를 반전시켜 1을 더한다"라는2개의 보완 방법을 사용합니다.
- 비트 반전: 0000
- 1: 0001 추가
0001은 10진수 1이므로 1111은 -1입니다.
쌍보법은 양방향이므로 임의의 숫자와 함께 사용할 경우 반전 부호가 있는 해당 숫자의 이진 표현을 제공합니다.
그럼 1000을 봅시다.첫 번째 비트는 1이므로 음수입니다.2개의 보완 방법을 사용합니다.
- 비트 반전: 0111
- 1: 1000(10진수 8)을 더합니다.
1000에서 -8로 하다.-(-8)
에서는 2를 -(1000)
.1000의 1000달러'4'가 됩니다.-(-8)
8입니다.
의 경우 32비트입니다.-2147483648
에서는 「」입니다.1000..(31 zeroes)
단, 2분할 방식을 사용하면 같은 값이 됩니다(결과는 같은 번호).
때문에 번호의 32비트 번호입니다.-(-2147483648)
-2147483648
(고정되지 않은) 정수 상수 부정:
.-(-2147483648)
C에 완벽하게 정의되어 있지만, 왜 이런지는 분명하지 않을 수 있습니다.
쓸 때-2147483648
정수 정수에 적용되는 단항 마이너스 연산자로 형성됩니다. if2147483648
로 수 int
는 s라고 long
★★★★★★★★★★★★★★★★★」long long
* (어느 쪽이 먼저 적합한가) C 표준이 후자의 유형을 보증하는 경우 해당† 값을 포함하도록 한다.
이것을 확인하려면 , 다음의 방법으로 조사할 수 있습니다.
printf("%zu\n", sizeof(-2147483648));
그 결과8
내 기계로.
는 두 하면 됩니다.-
은 '''입니다)2147483648L
(이)로 .long
에int
브브,, 음음음음음음음
int n = -(-2147483648);
실제 동작은 구현 정의됩니다.기준 참조:
C11 § 6.3.1.3 부호 있는 정수 및 부호 없는 정수
그렇지 않으면 새로운 유형이 서명되어 값이 그 유형에 표시될 수 없습니다.결과가 구현 정의되거나 구현 정의 신호가 발생합니다.
가장 일반적인 방법은 단순히 상위 비트를 차단하는 것입니다.예를 들어 GCC는 다음과 같이 문서화합니다.
폭 N의 종류로 변환하는 경우에는 모듈로 2^N을 감소시켜 그 종류 범위 내로 하고 신호는 상승하지 않는다.
개념적으로 폭 32의 유형으로의 변환은 비트 AND 연산에 의해 설명될 수 있다.
value & (2^32 - 1) // preserve 32 least significant bits
2의 덧셈 산술에 따르면, 의 값은n
는 모든 (부호) 비트세트는 MSB(MSB(부호)는 MSB(부호)의 값을 ).것은,, 음음음음음 음음음음음음음-2^31
, 「」, 「」-2147483648
.
int
★★★★★★★★★★★★★★★★★★:
하려고 int
가 있는 오브젝트, 을 of of of of of of of 의 가치를 갖는 객체-2147483648
그 후, 2개의 보완 머신이 있다고 가정하면, 프로그램은 정의되지 않은 동작:
n = -n; // UB if n == INT_MIN and INT_MAX == 2147483647
C11 6 6.5/5 식
식을 평가하는 동안 예외 조건이 발생하면(즉, 결과가 수학적으로 정의되지 않았거나 해당 유형에 대해 나타낼 수 있는 값의 범위에 포함되지 않은 경우) 동작은 정의되지 않습니다.
기타 참고 자료:
표준에는 *) C90이 .long long
유형과 규칙이 달랐습니다.되지 않은 는 '10'이었다int
,long int
,unsigned long int
(C90 『 6.1.3.2』).
② 이는 다음과 같습니다.LLONG_MAX
()은 되어야 합니다+9223372036854775807
(C11 § 5.2.4.2.1/1)
'에 대한 32비트2의 이 특징인C 은 C.C의 실장에서는 타입에 대한 32비트2의 보완표현이 특징입니다.int
를 「」에 int
가 -2147483648
정의되어 있지 않습니다.즉, C언어는 이러한 연산의 평가 결과를 지정하는 것을 명시적으로 거부합니다.
되는지를 보다 해 봅시다.-
연산자는 2의 보완 산술에서 정의된다: 양의 숫자 x의 역수는 그것의 이진 표현의 모든 비트를 플립하고 추가함으로써 형성된다.1
이 정의는 부호 비트 세트 이외의 비트가 적어도1개 있는 음수에도 적용됩니다.
단, 값 비트가 전혀 설정되어 있지 않은0과 부호 비트만 설정되어 있는 번호(32비트 표현에서는 2147483648)의 2개의 번호에 대해서는 경미한 문제가 발생합니다.이들 중 하나의 비트를 모두 플립하면 모든 값 비트가 설정됩니다.따라서 나중에 1을 추가하면 결과에서 값 비트가 오버플로우됩니다.숫자가 부호 없는 것처럼 덧셈을 수행하고 부호 비트를 값 비트로 처리한다고 가정하면 다음과 같이 됩니다.
-2147483648 (decimal representation)
--> 0x80000000 (convert to hex)
--> 0x7fffffff (flip bits)
--> 0x80000000 (add one)
--> -2147483648 (convert to decimal)
0의 반전에도 동일하게 적용되지만, 이 경우 1을 더했을 때의 오버플로우도 erstwhile 부호 비트를 오버플로합니다.오버플로를 무시하면 결과 32개의 하위 비트가 모두 0이 되므로 -0 == 0이 됩니다.
주의: 이 답변은 아직 많은 컴파일러에서 사용되고 있는 구식 ISO C90 규격에는 적용되지 않습니다.
먼저 C99, C11에서 표현은-(-2147483648) == -2147483648
사실 거짓입니다.
int is_it_true = (-(-2147483648) == -2147483648);
printf("%d\n", is_it_true);
인쇄하다
0
그래서 어떻게 이것이 사실로 평가될 수 있을까요?이 기계는 32비트 2의 보완 정수를 사용하고 있습니다.그2147483648
32비트에 맞지 않는 정수 정수이므로 다음 중 하나가 됩니다.long int
또는long long int
어떤 것이 가장 먼저 들어가는지에 따라 다르죠.이 부정으로 인해-2147483648
- 다시 말씀드리지만, 그 수는-2147483648
32비트 정수에 들어갈 수 있습니다.-2147483648
32비트 이상의 양의 정수 뒤에 유니리가 붙습니다.-
!
다음 프로그램을 사용해 볼 수 있습니다.
#include <stdio.h>
int main() {
printf("%zu\n", sizeof(2147483647));
printf("%zu\n", sizeof(2147483648));
printf("%zu\n", sizeof(-2147483648));
}
이러한 머신에서의 출력은 4, 8, 8이 될 가능성이 높습니다.
지금이다,-2147483648
부정은 다시 초래된다+214783648
, 이것은 아직 형식입니다.long int
또는long long int
, 그리고 모든 것이 정상입니다.
C99, C11에서는 정수 상수식은-(-2147483648)
는, 모든 준거 실장에 대해서 명확하게 정의되어 있습니다.
이 값이 유형 변수에 할당되면int
32비트와 2의 보완표현이 있는 경우, 32비트2의 보완표시의 값은 -2147483648 ~2147483647 의 범위입니다.
C11 표준 6.3.1.3p3에서는 다음과 같은 정수 변환이 규정되어 있습니다.
- 새로운 타입이 서명되어 값을 나타낼 수 없는 경우, 결과가 구현 정의되거나 구현 정의 신호가 발생합니다.
즉, C 표준은 이 경우의 값을 실제로 정의하지 않으며, 또한 신호 발생으로 인해 프로그램 실행이 중지될 가능성을 배제하지 않고, 이를 처리하는 방법을 결정하는 것을 구현(즉, 컴파일러)에 맡깁니다(C11 3.4.1).
구현 정의 동작
각 구현이 선택 방법을 문서화하는 지정되지 않은 동작
구현정의값
각 구현에서 선택 방법을 문서화하는 지정되지 않은 값
이 경우 구현 정의 동작은 값이 가장 낮은 32비트[*]인 것입니다.2의 보완으로 인해 (긴) long int 값은0x80000000
는 비트 31을 설정하고 다른 모든 비트를 클리어합니다.32비트 2의 보완정수에서 비트 31은 부호 비트입니다. 즉, 숫자가 음수임을 의미합니다. 0으로 설정된 모든 값 비트는 값이 최소 표현 가능한 숫자임을 의미합니다.INT_MIN
.
[*] GCC는 이 경우 구현 정의 동작을 다음과 같이 문서화합니다.
그 타입의 오브젝트(C90 6.2.1.2, C99 및 C11 6.3.1.3)로 나타낼 수 없는 경우에, 그 타입의 정수를 부호 있는 정수 타입으로 변환한 결과 또는 에 의해서 발생하는 신호.
폭 유형으로 변환하는 경우
N
, 값은 감소 모듈로입니다.2^N
유형 범위 내에 있어야 합니다. 신호는 발생하지 않습니다.
C의 버전, 구현의 세부 사항 및 변수와 리터럴 값 중 어느 것에 대해 이야기하고 있는지에 따라 달라집니다.
가장 먼저 이해해야 할 것은 C-2147483648에는 음의 정수 리터럴이 없다는 것이다.
int와 long이 모두 32비트이고 long이 64비트인 일반적인 32비트 플랫폼에서 실행되고 있다고 가정하고 식을 고려합니다.
(-(-2147483648) == -2147483648 )
컴파일러는 2147483648을 유지할 수 있는 타입을 찾아야 합니다.컴포밍 C99 컴파일러에서는 타입 "long"을 사용하지만 C90 컴파일러에서는 타입 "unsigned long"을 사용할 수 있습니다.
컴파일러가 long 타입을 사용하는 경우 오버플로우는 없으며 비교는 거짓입니다.컴파일러가 부호 없는 long을 사용하는 경우 부호 없는 랩어라운드 규칙이 적용되어 비교가 참입니다.
같은 이유로 테이프 데크 카운터를 000에서 500단계 앞으로 감으면(001 002 003을 통해) 500이 표시되고, 테이프 데크 카운터를 000에서 500단계 뒤로 감으면(99998 997을 통해) 500이 됩니다.
이것은 2의 보어 표기법입니다.물론 2의 보완 부호 규칙은 최상위 비트를 부호 비트로 간주하는 것이기 때문에, 2000000000+2000000000이 표시 범위를 오버플로하는 것과 마찬가지로 결과도 표시 범위를 오버플로합니다.
그 결과 프로세서의 "오버플로우" 비트가 설정됩니다(이를 위해서는 일반적으로 어셈블러 이외의 대부분의 프로그래밍 언어에서는 그렇지 않습니다).이 값은 2의 보완 번호를 부정할 때 "오버플로" 비트를 설정하는 유일한 값입니다. 다른 값의 부정은 2의 보완으로 나타낼 수 있는 범위에 있습니다.
언급URL : https://stackoverflow.com/questions/42462352/why-is-2147483648-2147483648-in-a-32-bit-machine
'programing' 카테고리의 다른 글
디버거를 사용하지 않는 경우에만 segfault가 발생합니다. (0) | 2022.08.10 |
---|---|
Vue $route가 정의되지 않았습니다. (0) | 2022.08.10 |
Vuex 스토어를 Storybook으로 작동시키려면 어떻게 해야 하나요? (0) | 2022.08.10 |
Vue/Vuex - JSON 파일에서 로드 상태 (0) | 2022.08.10 |
C에서 플렉시블 어레이 멤버를 사용하는 것은 나쁜 방법입니까? (0) | 2022.08.10 |