부호 없는 정수 빼기는 정의된 동작입니까?
같은 타입의 다른 정수에서 부호 없는 정수를 빼는 데 문제가 있다고 생각되는 사람으로부터 코드가 발견되었는데, 결과는 음수입니다.따라서 이러한 코드는 대부분의 아키텍처에서 작동하더라도 정확하지 않습니다.
unsigned int To, Tf;
To = getcounter();
while (1) {
Tf = getcounter();
if ((Tf-To) >= TIME_LIMIT) {
break;
}
}
C 기준에서 모호하게 관련된 인용구는 이것밖에 없습니다.
부호 없는 피연산자를 포함한 계산은 절대 오버할 수 없습니다.이는 결과 부호 없는 정수형으로 나타낼 수 없는 결과가 결과 유형으로 나타낼 수 있는 최대값보다 1 큰 수치로 감소하기 때문입니다.
이 인용문은 오른쪽 피연산자가 더 클 때 연산이 모듈로 잘린 숫자의 맥락에서 의미 있게 조정된다는 의미로 해석할 수 있을 것 같습니다.
예.
0x0000 - 0x0001 == 0x1 0000 - 0x0001 == 0xFFFF
구현에 의존한 서명된 의미론 사용과는 달리 다음과 같습니다.
0x0000 - 0x0001 == (부호 없음) (0 + - 1) == (0xFFFFF, 0xFFE 또는 0x8001)
어떤 해석이 옳은가?정의되어 있나요?
부호 없는 타입으로 작업할 때는 모듈러 연산(「감기」동작이라고도 불립니다)이 실행됩니다.이 모듈식 계산을 이해하려면 다음 클럭을 참조하십시오.
9 + 4 = 1(13 mod 12)이므로 반대 방향은 1 - 4 = 9(-3 mod 12)입니다.서명되지 않은 유형을 사용할 때도 동일한 원리가 적용됩니다.결과 유형이 다음과 같은 경우unsigned
하다
이제 결과를 저장하기 위한 다음 작업을 살펴보겠습니다.unsigned int
:
unsigned int five = 5, seven = 7;
unsigned int a = five - seven; // a = (-2 % 2^32) = 4294967294
int one = 1, six = 6;
unsigned int b = one - six; // b = (-5 % 2^32) = 4294967291
를 확인하고 때signed
에 해 두었습니다.signed
그것을 가변 또는 캐스팅하다signed
숫자의 차이를 구하고 모듈식 산술이 적용되지 않도록 하려면 에서 정의한 함수를 사용하는 것을 고려해야 합니다.stdlib.h
:
int c = five - seven; // c = -2
int d = abs(five - seven); // d = 2
특히 쓰기 조건 중에는 다음과 같은 이유로 매우 주의해야 합니다.
if (abs(five - seven) < seven) // = if (2 < 7)
// ...
if (five - seven < -1) // = if (-2 < -1)
// ...
if (one - six < 1) // = if (-5 < 1)
// ...
if ((int)(five - seven) < 1) // = if (-2 < 1)
// ...
그렇지만
if (five - seven < 1) // = if ((unsigned int)-2 < 1) = if (4294967294 < 1)
// ...
if (one - six < five) // = if ((unsigned int)-5 < 5) = if (4294967291 < 5)
// ...
부호 없는 유형의 음수를 생성하는 감산 결과는 명확하게 정의됩니다.
- [...] 부호 없는 피연산자를 포함한 계산은 결코 오버플로우 할 수 없다. 왜냐하면 부호 없는 정수형으로는 나타낼 수 없는 결과는 결과형으로는 나타낼 수 있는 가장 큰 값보다 1 큰 수치로 감소하기 때문이다.(ISO/IEC 9899:1999 (E) § 6.2.5/9)
바와 같이, '우리'는 '우리'입니다.(unsigned)0 - (unsigned)1
또는1 modulo UINT_MAX+1, "UINT_MAX"와 .
"부호되지 않은 피연산자를 포함하는 계산은 절대 오버플로할 수 없습니다"라고 되어 있는데, 이는 상한 초과에만 적용되는 것으로 생각될 수 있지만, 이는 문장의 실제 바인딩 부분에 대한 동기 부여로 제시됩니다: "결과적인 부호되지 않은 정수 유형으로 나타낼 수 없는 결과는 감소된 모듈입니다."o 결과 유형으로 나타낼 수 있는 최대값보다 1 큰 숫자입니다."이 문구는 유형의 상한 오버플로로 제한되지 않으며 너무 낮아 나타낼 수 없는 값에도 동일하게 적용됩니다.
부호 없는 정수 빼기는 동작을 정의해 왔습니다.또한 어려운 일입니다.부호 없는 두 정수를 빼면 결과(lvalue) 유형이 명시적으로 지정되지 않은 경우 결과가 더 높은 유형 int로 승격됩니다.예를 들어 후자의 경우 int8_t result = a - b; (a 및 b의 int8_t 타입) 매우 이상한 동작을 얻을 수 있습니다.즉, 트랜시비티 속성을 잃을 수 있습니다(즉, a > b 및 b > c의 경우 a > c의 경우).이동성이 상실되면 트리형 데이터 구조 작업이 파괴될 수 있습니다.어떤 키가 더 높거나 더 낮은지 추론하기 위해 부호 없는 정수 감산을 사용하는 정렬, 검색, 트리 구축을 위한 비교 기능을 제공하지 않도록 주의해야 합니다.
아래의 예를 참조해 주세요.
#include <stdint.h>
#include <stdio.h>
void main()
{
uint8_t a = 255;
uint8_t b = 100;
uint8_t c = 150;
printf("uint8_t a = %+d, b = %+d, c = %+d\n\n", a, b, c);
printf(" b - a = %+d\tpromotion to int type\n"
" (int8_t)(b - a) = %+d\n\n"
" b + a = %+d\tpromotion to int type\n"
"(uint8_t)(b + a) = %+d\tmodular arithmetic\n"
" b + a %% %d = %+d\n\n",
b - a, (int8_t)(b - a),
b + a, (uint8_t)(b + a),
UINT8_MAX + 1,
(b + a) % (UINT8_MAX + 1));
printf("c %s b (b - c = %d), b %s a (b - a = %d), AND c %s a (c - a = %d)\n",
(int8_t)(c - b) < 0 ? "<" : ">", (int8_t)(c - b),
(int8_t)(b - a) < 0 ? "<" : ">", (int8_t)(b - a),
(int8_t)(c - a) < 0 ? "<" : ">", (int8_t)(c - a));
}
$ ./a.out
uint8_t a = +255, b = +100, c = +150
b - a = -155 promotion to int type
(int8_t)(b - a) = +101
b + a = +355 promotion to int type
(uint8_t)(b + a) = +99 modular arithmetic
b + a % 256 = +99
c > b (b - c = 50), b > a (b - a = 101), AND c < a (c - a = -105)
부호가 타입의 」unsigned int
유형 변환이 없는 경우, 또는 그 이상입니다.a-b
는 부호 되어 있습니다.이 숫자는, 「부호 없는 번호」에 됩니다.b
,가 산출됩니다.a
음수를 부호 없이 변환하면 부호 반전된 원래 숫자에 더하면 0이 된다(따라서 -5를 부호 없음으로 변환하면 5에 더하면 0이 된다).
는 보다 주의하세요.unsigned int
으로 될 수 .int
a-b
에 int
.
음, 첫 번째 해석은 맞습니다.그러나 이 맥락에서 "서명된 의미론"에 대한 당신의 추론은 틀렸습니다.
다시 한 번, 당신의 첫 번째 해석은 옳습니다.부호 없는 산수는 모듈로 산술의 규칙을 따르는데, 이것은 다음을 의미한다.0x0000 - 0x0001
까지 평가하다.0xFFFF
32비트 부호 없는 타입의 경우.
그러나 두 번째 해석('서명된 의미론'에 기초한 해석)도 동일한 결과를 얻기 위해 필요합니다.예를 들어, 당신이 평가한다고 해도0 - 1
서명된 활자의 영역에서, 그리고 얻습니다.-1
중간 결과로서 이것은-1
여전히 생산해야 합니다.0xFFFF
나중에 부호 없는 유형으로 변환됩니다.일부 플랫폼이 부호 있는 정수(1의 보완, 부호 있는 크기)에 대해 이국적인 표현을 사용하더라도 이 플랫폼은 부호 없는 정수 값을 변환할 때 모듈로 산술 규칙을 적용해야 합니다.
예를 들어 이 평가는
signed int a = 0, b = 1;
unsigned int c = a - b;
생산은 여전히 보장된다.UINT_MAX
에c
플랫폼이 부호 있는 정수에 대해 이국적인 표현을 사용하고 있는 경우에도 마찬가지입니다.
int d = abs(five - seven); // d = 2
std::abs는 부호 없는 정수의 경우 "signed"가 아닙니다.깁스가 필요하긴 한데.
언급URL : https://stackoverflow.com/questions/7221409/is-unsigned-integer-subtraction-defined-behavior
'programing' 카테고리의 다른 글
JpaTest 실행 시 @SpringBootConfiguration을 찾을 수 없음 (0) | 2022.08.01 |
---|---|
값이 완전히 업데이트되기 전에 Vue 3 워치가 호출됩니다. (0) | 2022.08.01 |
Java에서 어레이를 초기화하는 방법 (0) | 2022.08.01 |
Vuex getter가 클라이언트 측에서는 TRUE를 반환하고 서버 측에서는 FALSE를 반환하는 이유는 무엇입니까? (0) | 2022.08.01 |
v-html의 Vue 구성 요소/요소 (0) | 2022.08.01 |