서명되지 않은 부호로 변환에서는 C-그것은 항상 안전합니까?
-
09-06-2019 - |
문제
가정하자 나는 다음과 같은 C 코드입니다.
unsigned int u = 1234;
int i = -5678;
unsigned int result = u + i;
무엇을 암시적 변환을에 여기에,그리고 이 코드에 대한 안전의 모든 값 u
고 i
?(안전하다는 의미에서도 불구 결과 이 예시에서 오버플로우하는 몇몇 거대한 양수,나는 그것을 다시 int 와 실제 결과입니다.)
해결책
짧은 대답
귀하의 i
될 것입 변환 을 부호 없는 정수에 의해 추가 UINT_MAX + 1
, 다음을 추가로 수행됩 서명되지 않은 값의 결과로,큰 result
(값에 따라 u
고 i
).
긴 답변
에 따라 C99 표준:
6.3.1.8 일반적인 산술 전환
- 는 경우에는 모두 피연산자가 동일한 유형이 더 이상의 전환이 필요합니다.
- 그렇지 않은 경우,피연산자가 모두 서명한 정수 형식 또는 모두가 서명되지 않는 정수형,피연산자의 형식과 더 적은 정수로 변환 순위로 변환하여 피연산자의 유형으로 더 큰 순위입니다.
- 그렇지 않은 경우,피연산자가 서명되지 않는 정수형 순위가 크거나 같음의 계급의 유형이 다른 연산자,그 다음 연산자로 서명된 정수형 변환기 유형 피연산자의 부호 없는 정수형입니다.
- 그렇지 않은 경우,형식 피연산자의 서명된 정수 입력할 수 있습을 나타내의 모든 값의 형식 피연산자의 서명이 없는 정수형,다음 연산자와 부호 없는 정수형 변환기 유형 피연산자의 서명된 정수 입력.
- 그렇지 않으면 모두 피연산자로 변환된 부호 없는 정수형 해당하는 유형 피연산자의 서명된 정수 입력.
귀하의 경우에,우리는 하나 unsigned int(u
고)signed int(i
).참조(3)위에,이후 피연산자를 모두 동일한 순위를 가지고,당신 i
야 합니다 변환 을 부호 없는 정수입니다.
6.3.1.3 서명 및 부호 없는 정수
- 할 때 가치와 정수형 변환기 또는 정수형 이외의 다른 _Bool 는 경우,이 값을 표현할 수 있는 새로운 유형,그것은 변경되지 않습니다.
- 그렇지 않은 경우,새로운 유형이 서명되지 않은 값이 변환되는 반복적으로 추가하거나 빼는 하나 이상의 최대값을 표현할 수 있는 새로운 유형 될 때까지 가치의 범위에 새로운 유형입니다.
- 그렇지 않으면,새로운 유형이 서명되고 가치로 표현할 수 없다;거나 결과는 구현 시 정의는 구현된 신호가 발생합니다.
지금 우리에게 필요한 참조(2)above.귀하의 i
로 변환되는 값을 추가하여 UINT_MAX + 1
.그래서 결과 방법에 따라 달라집니다 UINT_MAX
에 정의의 구현합니다.그것은 큰 것입니다,그러나지 않기 때문:
6.2.5 (9)
계산 관련 부호 없는 피연산자 수 없기 때문 결과로 표현할 수 없는 의 결과 unsigned integer 유형 감소한 모듈로는 숫자보다 가장 큰 가치로 표현할 수 있는 결과 유형입니다.
보너스:산술 변환 Semi-WTF
#include <stdio.h>
int main(void)
{
unsigned int plus_one = 1;
int minus_one = -1;
if(plus_one < minus_one)
printf("1 < -1");
else
printf("boring");
return 0;
}
당신이 링크를 사용할 수 있습니다 이것을 시도해 온라인: https://repl.it/repls/QuickWhimsicalBytes
보너스:산술 변환 Side Effect
산술 변환 규칙을 사용할 수 있는 값의 UINT_MAX
를 초기화하여 서명되지 않은 가치를 -1
, ie:
unsigned int umax = -1; // umax set to UINT_MAX
이식할 수에 관계없이 서명한 번호의 표현 시스템이기 때문에 변환의 규칙을 설명한다.이렇게 질문에 대한 더 많은 정보: 그것은 사용하기에 안전 -1 을 설정하는 모든 비트를 사실인가요?
다른 팁
변환에서 서명 서명되지 않는 지 은 반드시 복사본이나 해석해 표현의 서명된 값입니다.을 인용하는 C 표준(C99 6.3.1.3):
할 때 가치와 정수형 변환기 또는 정수형 이외의 다른 _Bool 는 경우 값을 표현할 수 있는 새로운 유형,그것은 변경되지 않습니다.
그렇지 않은 경우,새로운 유형이 서명되지 않은 값이 변환되는 반복적으로 추가하거나 을 빼서 하나 이상의 최대값을 표현할 수 있는 새로운 유형 까지는 값의 범위에서는 새로운 유형입니다.
그렇지 않으면,새로운 유형이 서명되고 가치로 표현할 수 없다;나 그 결과 구현 시 정의는 구현된 신호가 발생합니다.
에 대한 두 개의 보충 표현하는 거의 보편적인 요즘은 규칙에 해당한 재해석하는 비트입니다.하지만 다른 표현(호 및 크기 또는'보수),C 구현해야합니다 여전히 준비를 위해 동일한 결과,즉 변환할 수 있는지만 복사합니다.예를 들어,(unsigned)-1==uint_max 로 씁에 관계없이의 표현입니다.
일반적으로,변환 C 에서 정의된 작동 값에,지에 표현입니다.
대답을 원래의 질문:
unsigned int u = 1234;
int i = -5678;
unsigned int result = u + i;
I 의 값으로 변환하 unsigned int,항복 UINT_MAX + 1 - 5678
.이 값은 다음에 추가 서명되지 않은 가치 1234,항복 UINT_MAX + 1 - 4444
.
(와 달리 부호 없는 오버플로,서명 오버플로를 호출합 정의되지 않은 행동이다.랩어라운드는 일반적이지만,에 의해 보장되지 않으 C 표준--와 컴파일러 최적화할 수 있는 위력을 과시 코드에서는 부당한 모델 예측제어 등을 다룬다.)
조 성경:
- 또한 작업으로 인 int 로 변환할 unsigned int.
- 고 가정하고 두 개의 보충 표현하고 균일한 크기의 종류,비트 패턴을 변경하지 않습니다.
- 변환 unsigned int 을 서명 int 구현 방식에 따라 다릅니다.(그러나 그것은 아마이 작동 방법은 당신이 기대하는 대부분의 플랫폼에서 이러한 일입니다.)
- 이 규칙은 조금 더 복잡한 경우에 결합의 서명 및 서명 서로 다른 크기입니다.
한 때 서명이 없으며,하나의 서명된 변수 추가(또는 바이너리 작업)을 두는 암시적으로 변환 부호 없는 것,이 경우 그 결과에 큰 결과입니다.
그래서 그것은에서 안전 감각의 결과될 수 있습 거대한 잘못이지만,그것은 결코 충돌이 발생합니다.
변환할 때에 서명되지 않은 부호가 있는 두 가지 방법이 가능합니다.숫자는 긍정적인 유지(또는 해석 등)동일한 값입니다.는 번호가 원래 부정적인 것입니다 지금 해석할 수 있으로 더 긍정적인 숫자입니다.
으로 이전에 응답할 수 있습 캐스팅 사이 앞뒤로 서명 및 부호 없이 문제입니다.국경 경우 대한 서명된 정수이다 -1(0xFFFFFFFF).도 추가하고 빼는 사실을 발견할 수 있습으로 다시 캐스팅하고 있다.
그러나,당신이 할 것 주조,앞뒤로 나는 강하게 이름을 지정하는 변수는 무엇인 유형은 그들이는,예를 들어:
int iValue, iResult;
unsigned int uValue, uResult;
그것은 너무 쉽게 얻을 산만 더 중요한 문제를 잊어있는 변수가 무엇을 입력하는 경우 그들의 이름은 없습니다.당신이 원하지 않을 캐스팅하는 부호를 사용하여 다음을 배열로 인덱스입니다.
무엇을 암시적 변환을은 여기서,
i will be 변환 부호 없는 정수입니다.
이 코드에 대한 안전의 모든 값 u 나는?
에서 안전 감각의 정의 예(참조하십시오 https://stackoverflow.com/a/50632/5083516 ).
규칙을 작성에는 일반적으로 열심히 읽고 표준-말을하지만 본질적으로 어떤 표현에서 사용되었다수의 부호 없는 정수를 포함한 2 개의 보수 표현의 번호입니다.
또한,빼기와 곱게 올바르게 작동에 이 숫자의 결과로 다른 부호 없는 정수를 포함하는 조로 보완 수를 나타내는"실제 결과".
분단과 캐스팅을 크 unsigned integer 유형이 잘 정의된 결과 하지만 그 결과를 얻을 수 없습 2 보수의 표현이"진짜 결과".
(안전하다는 의미에서도 결과는 이 예에서 오버플로우하는 몇몇 거대한 양수,나는 그것을 다시 int 와 실제 결과입니다.)
는 동안 변환에서 서명 서명되지 않는 정의된 기준에 의해 반전 구현 시 정의를 모두 gcc 및 msvc 정의 변환과 같은 당신을 얻을 것이"진짜 결과는"변환하는 경우 2 의 보수에 저장되는 부호 없는 정수를인 정수입니다.나는 당신을 기대를 만날 수 있는 것은 다른 어떤 행동을 보호 시스템을 사용하지 않는 2 개의 보충에 대한 서명된 정수입니다.
https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation https://msdn.microsoft.com/en-us/library/0eex498h.aspx
끔찍한 답변의 풍부한 맛
Ozgur Ozcitak
을 때 당신이 던지기에서 서명 서명되지 않음 (그리고 반대로)부 의 표현하지 않는 번호 변경합니다.어떤 변화가 어떻게 컴파일러 해석 등 비트입니다.
이는 완전히 잘못된 것입니다.
매트 Fredriksson Sekab
한 때 서명이 없으며,하나의 서명 변수 추가(또는 바이너리 운전)모두는 암시적으로 변환 부호 없는 것에 이 경우 그 결과에 큰 결과입니다.
이것은 잘못된 것입니다.Unsigned 수 있으로 승진 수야 그들이 동일한 정밀도로 인해 패딩의 비트 부호 없는 유형입니다.
다.
또한 작업으로 인 int 로 변환할 unsigned int.
잘못입니다.어쩌면 그것은 어쩌면 그것을 하지 않습니다.
변환 unsigned int 을 서명 int 구현 방식에 따라 다릅니다.(지 그것은 아마이 작동 방법은 당신이 기대하는 대부분의 플랫폼에서 이러한 일입니다.)
잘못입니다.그것은 하나 정의되지 않은 동작을 일으키는 원인이 되면 오버플로나의 값이 유지됩니다.
익명
I 의 값으로 변환됩 unsigned int...
잘못입니다.의 정밀도에 따라 달라 집 int 관 unsigned int.
테일러 가격
으로 이전에 응답할 수 있습 주 앞뒤로 사이에 서명하고 서명없이 문제입니다.
잘못입니다.를 저장하는 값의 범위 밖에 서명된 정수의 결과에서 정의되지 않은 행동이다.
지금 마지막 질문에 대답.
해 정밀도의 int 같 unsigned int,u 로 승격되고 서명된 int 고 당신은 값을 얻을 것이다 -4444 에서 식(u+i).이제,한 u 하고 나는 다른 값을 얻을 수 있습니다 오버플로 정의되지 않은 행동하지만 그 정확한 숫자을 얻을 것이 -4444 [1].이 값이 유형 int.그러나 당신이 시도하고 있는 저장하는 값으로 unsigned int 는 것입니다 그래서 그 다음 주에는 unsigned int 와 가치는 결과가 끝나는 것(uint_max 로 씁+1)-4444.
해야의 정밀도 unsigned int 것보다 큰 int,서명된 int 것으로 승격되 unsigned int 산출 가치(uint_max 로 씁+1)-5678 에 추가될 다른 unsigned int1234.해야 u 하고 나는 다른 값을 표현 범위를 벗어{0..uint_max 로 씁}값(uint_max 로 씁+1)하나 추가하거나 뺄 때까지는 결과가 떨어질 내부 범위{0..uint_max 로 씁)없이 정의되지 않은 문제가 발생합니다.
는 무엇입 정밀?
정수 있 패딩 비트,로그인 비트값 비트입니다.호 정수 없는 등록금 분명합니다.Unsigned char 이 더 보장하지 않는 여백 비트입니다.수은 값의 비트 정수가 얼마나 정밀도니다.
[문제점]
매크로 sizeof 매크로 혼자 사용할 수 없습을 결정하는 정밀의 정수한 경우 패딩 비트가 존재한다.의 크기는 바이트 수 없는 옥텟(eight bits)에 의해 정의된 C99.
[1] 오버플로우가 발생할 수 있습 중 하나에서 두 개의 포인트입니다.하나 추가하기 전에(이용촉진)-이 있는 경우 unsigned int 는 맞게 너무 큰 내부 int.오버플로우가 발생할 수 있습 후한 경우에도 unsigned int 었의 범위 내에서 int,첨가한 후 그 결과는 여전히 오버플로우가 발생합니다.
에 없는 나는 최근 대학원 학생을 찾으려고 일)