C에서 부호 있는 변수와 부호 없는 변수에 대한 설명을 둘러보세요.

StackOverflow https://stackoverflow.com/questions/19842215

  •  29-07-2022
  •  | 
  •  

문제

나는 부호 없는 변수(특히 부호 없는 짧은 int) 소위 일부를 수행합니다. 줄 바꿈 정수 오버플로에서 내가 남긴 것 외에는 서명된 변수에서 아무것도 찾을 수 없었지만 정의되지 않은 동작.

교수님은 그들의 가치도 포장되어 있다고 말씀하셨습니다. (아마도 그는 단지 gcc를 의미했을 것입니다.)나는 비트가 잘려서 남겨진 비트가 나에게 이상한 값을 제공한다고 생각했습니다!

랩 어라운드(wrap around)란 무엇이며 비트를 자르는 것과 어떻게 다릅니까?

도움이 되었습니까?

해결책

부호 있는 정수 변수에는 C 언어에서 랩어라운드 동작이 없습니다.산술 계산 중 부호 있는 정수 오버플로로 인해 정의되지 않은 동작.당신이 언급한 GCC 컴파일러는 구현으로 알려져 있습니다. 엄격한 오버플로 의미 최적화에서는 정의되지 않은 동작 상황에서 제공되는 자유를 활용한다는 의미입니다.GCC 컴파일러는 부호 있는 정수 값이 절대 순환되지 않는다고 가정합니다.이는 GCC가 실제로 당신이 사용하는 컴파일러 중 하나라는 것을 의미합니다. 할 수 없다 부호 있는 정수 유형의 랩 어라운드 동작에 의존합니다.

예를 들어, GCC 컴파일러는 변수에 대해 다음과 같이 가정할 수 있습니다. int i 다음 조건

if (i > 0 && i + 1 > 0)

단순한 것과 동일하다

if (i > 0)

바로 이것이다 엄격한 오버플로 의미 수단.

부호 없는 정수 유형은 모듈로 산술을 구현합니다.모듈로는 동일합니다. 2^N 어디 N 유형의 값 표현에 있는 비트 수입니다.이러한 이유로 부호 없는 정수 유형은 실제로 오버플로 시 래핑되는 것처럼 보입니다.

그러나 C 언어는 C 언어보다 작은 영역에서 산술 계산을 수행하지 않습니다. int/unsigned int.유형 unsigned short int 귀하의 질문에서 언급한 내용은 일반적으로 다음 유형으로 승격됩니다. int 계산이 시작되기 전 표현식에서(범위가 다음과 같다고 가정) unsigned short 의 범위에 들어맞는다 int).이는 1) 다음과 같은 계산을 의미합니다. unsigned short int 의 영역에서 수행될 예정이다. int, 다음과 같은 경우 오버플로가 발생합니다. int 2) 이러한 계산 중 오버플로는 랩 어라운드 동작이 아닌 정의되지 않은 동작으로 이어집니다.

예를 들어, 이 코드는 랩 어라운드를 생성합니다.

unsigned i = USHRT_MAX;
i *= INT_MAX; /* <- unsigned arithmetic, overflows, wraps around */

이 코드는 동안

unsigned short i = USHRT_MAX;
i *= INT_MAX; /* <- signed arithmetic, overflows, produces undefined behavior */

정의되지 않은 동작으로 이어집니다.

그렇지 않은 경우 int 오버플로가 발생하고 결과는 다시 unsigned short int 유형, 다시 모듈로로 감소됩니다. 2^N, 이는 값이 래핑된 것처럼 나타납니다.

다른 팁

너비가 3 비트에 불과한 데이터 유형이 있다고 상상해보십시오. 이를 통해 0에서 7까지의 8 개의 별개의 값을 나타낼 수 있습니다. 1에서 7을 추가하면 값 8 (1000)을 나타내는 비트가 충분하지 않기 때문에 0으로 다시 "랩"됩니다.

이 동작은 서명되지 않은 유형에 대해 잘 정의되어 있습니다. 그것은이다 ~ 아니다 서명 된 값을 나타내는 여러 가지 방법이 있기 때문에 서명 된 유형에 대해 잘 정의되어 있으며 오버플로의 결과는 해당 방법에 따라 다르게 해석됩니다.

기호-최상위 비트는 부호를 나타냅니다. 0의 경우 0, 1은 음수입니다. 내 유형이 다시 3 비트 너비 인 경우 다음과 같이 서명 된 값을 나타낼 수 있습니다.

000  =  0
001  =  1
010  =  2
011  =  3
100  = -0
101  = -1
110  = -2
111  = -3

부호를 위해 하나의 비트가 사용되므로 0에서 3까지의 값을 인코딩하는 두 비트 만 있습니다. 예, 0에 대한 두 가지 표현이 있습니다. 당신은 종종 사인-크기 표현을 마치지 않을 것입니다.

하나의 보수 : 음수 값은 양수 값의 비트 방향입니다. 다시, 3 비트 유형을 사용합니다.

000  =  0
001  =  1
010  =  2
011  =  3
100  = -3
101  = -2
110  = -1 
111  = -0

내 값을 인코딩하는 세 가지 비트가 있지만 범위는 [-3, 3]입니다. 1 ~ 3을 추가하면 결과적으로 -3로 오버플로를 올릴 것입니다. 이는 위의 부호가있는 결과와 다릅니다. 다시,이 방법을 사용하여 0에 대한 두 가지 인코딩이 있습니다.

두 가지 보수 : 음수 값은 양수 값의 비트 역수입니다. 3 비트 시스템에서 :

000  =  0
001  =  1
010  =  2
011  =  3
100  = -4
101  = -3
110  = -2
111  = -1

1 ~ 3을 추가하면 결과적으로 -4로 오버플로를 올리며 이전 두 가지 방법과 다릅니다. 우리는 약간 더 큰 값의 값을 가지고 있으며 [-4, 3] 0에 대한 하나의 표현 만 있습니다.

2의 보완은 아마도 서명 된 값을 나타내는 가장 일반적인 방법 일지 모르지만, 이는 유일한 것이 아니므로 C 표준은 서명 된 정수 유형을 넘어서서 어떤 일이 일어날 지 보장 할 수 없습니다. 그래서 그것은 행동을 남깁니다 한정되지 않은 따라서 컴파일러는 여러 표현을 해석 할 필요가 없습니다.

그만큼 정의되지 않은 행동 서명 된 정수 유형이 부호 및 크기, 보완 또는 2의 보완으로 표시 될 수있는 초기 휴대 성 문제에서 비롯됩니다.

요즘 모든 아키텍처는 정수를 감싸는 2의 보완으로 나타납니다. 그러나 조심하십시오 : 컴파일러가 정의되지 않은 동작을 실행하지 않을 것이라고 가정 할 수 있기 때문에 최적화가 켜져있을 때 이상한 버그가 발생할 수 있습니다.

서명 된 8 비트 정수에서 랩 주위의 직관적 인 정의는 +127에서 -128로가는 것처럼 보일 수 있습니다. 보시다시피, 그것은 정수, 서명 또는 서명되지 않은 정수를 나타내는 것을 고려할 때 이진 데이터를 증가시키는 자연스러운 진행입니다. 직관적으로, 실제 오버플로는 서명되지 않은 정수의 랩 어라운드 감각에서 -1 (11111111)에서 0 (00000000)으로 이동할 때 발생합니다.

이것은 표준에 따라 "올바른"동작이 없기 때문에 서명 된 정수가 오버플로 될 때 올바른 동작이 무엇인지에 대한 더 깊은 질문에 대답하지 않습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top