Thursday, July 27, 2006

카운터,시간에 unsigned int 를 사용하는 것

카운터나 시간 등을 담기 위해 자료형으로 unsigned int 를 종종 사용한다. 그러나 unsigned 를 사용하는 경우, "비교"하는 부분에서 문제가 생기곤 한다. 시간이나 카운터의 경우, 값이 점점 증가하거나 감소한다. 그러나 자료형의 크기를 넘어서면 오버플로가 발생한다. 여기서, signed를 사용할 경우 두 값의 차이가 아주 크지 않은 경우 오류가 발생하지 않지만, unsigned의 경우 오류가 발생한다.
두개의 unsigned 변수 a,b가 점점 증가한다. 그러다가 만약 a=4294967295 (unsigned int의 최대값)이 되었고, b는 그 값보다 1 큰 수가 되었다고 가정하자. 그런데 b는 unsigned int 의 최대 범위를 넘어서는 바람에 오버플로우가 났고 값이 0이 되어 버렸다. 다음 예를 보자.

unsigned int a=4294967295; unsigned int b=4294967295; b++;
printf("%u<%u ? \n",a,b); if(a
실행결과는 아래와 같다.
4294967295<0 ? false

이런! 결과가 틀리게 되어 버렸다. 이런 식의 결과는 시스템의 심각한 오동작을 야기할 수 있다.
그럼, 이 변수들을 부호있는 int로 사용해보자.

int a=4294967295; int b=4294967295; b++;
printf("%d<%d ? \n",a,b); if(a
실행결과는 아래와 같다.
-1<0 ? true

제대로 나온다. 비록 음수이긴 하지만, a=b 상황에서 b값을 좀 증가시켰으니, a
그러나, 다음 상황을 보자. a는 4294967295의 절반값인 2147483647, b는 그것에 1을 더한 값을 가지고 있는 경우를 보자. (코드는 생략)
2147483647<-2147483648 ? false

이래서는 안된다!. 그러나 비교문을 쓰지 말고 빼기를 수행해서 그것이 음수인지 양수인지 판단하는 스타일로 해보자. 즉, ab는 a-b>0으로 조건표현을 바꾼다. 아래와 같이 코드를 수정해 보았다.
int a=4294967295/2; int b=4294967295/2; b++;
printf("%d<%d ? \n",a,b); if (a-b<0) printf("true\n"); else printf("false\n");

수행결과는 다음과 같다.
2147483647<-2147483648 ? true

이것은 a와 b를 4294967295로 했을 경우에도 잘 동작한다.

결국, 타이머 관리나 카운터 관리 등을 위한 변수를 사용할 경우, 오버플로우가 예상되는 경우에는 unsigned 대신에 signed 자료형을 쓰고, 비교는 빼기를 이용하는 것이 안전하다. 꼭 알아두기 바란다. (필자도 이러한 문제 때문에, 타이머 이벤트가 뜨지 않아 고생했었던 기억이 있다)

No comments :