|
printf함수 같은 전통적인 C함수 들은 형변환에 취약합니다.
printf함수의 동작은 va_list등의 함수를 이용하여 가변적인 인자를 스택에 저장한 후 전달합니다.
"%f %d" 와같은 인자를 읽어들여 %f일경우 실수로, %d일경우 정수로 스택에 담긴 값을 읽어들이게 됩니다. 문제는 여기서 발생합니다. 읽어들일때 printf는 절대 형변환을 하지 않습니다.
예를 들어
printf("answer2 is the real %f\n", 9/4);
이 부분의 경우 9/4는 정수연산이므로 이미 2라는 정수값으로 스택에 저장되어 있습니다. 인자의 형태는 %f로 지정하였으므로 printf는 float형으로 읽어들이게 됩니다. 하지만 (float)라는 식의 캐스팅은 하지않고 메모리를 직접 float형으로 읽어버립니다.
캐스팅은 컴파일러가 직접해주는 형 변환입니다. 정수와 실수는 같은 1을 표현하더라도 메모리에 다르게 저장됩니다. 실수의 경우 지수부와 가수부 등이 비트별로 나뉘어 저장되고 컴파일러는 그것을 관리합니다. (float),(int)와 같은 캐스팅이 발생하면 컴파일러는 형 변환을 수행하게 되구요.
이와같은 캐스팅 없이 바로 메모리를 읽어들이게 되면 정수값이 들어있는 각 비트는 더이상 의미가 없게 됩니다. 그 반대의 경우도 마찬가지겠지요. 이미 스택에 저장된 값을 틀이 깨져버렸으니 그 다음에 연속으로 인자를 구성한다 하더라도 이미 오동작을 하게될겁니다.
printf("answer3 is the integer %d %d %d %d\n",(float)2,12,13);
위 부분을 bcc5.5를 사용하여 출력한 결과
answer3 is the integer 0 1073741824 12 13
처럼 나타납니다. 인자는 3개를 주었고 출력은 4개인데 처음 두 값은 망가져있고 나머지 두 값이 출력됩니다. printf는 인자를 오른쪽에서 왼쪽으로 넘기므로 13,12는 스택에 잘 들어갔고 (float)2에서 값이 엉망으로 들어간거지요...심심하시면 직접 분석을 해보시는것도..-.-...bcc5.5가 32비트이다보니...자리수가 너무 길어 엄두가 안나는군요...
ntn 님이 쓰신 글 :
: 안녕하세요... 다름이 아니라 아래 프로그램에서 형변환은 알겠는데...
:
: 실수형을 정수형으로 출력할때나 정수형을 실수형으로 출력할때 결과값이 0이나 -값이 나와서
:
: 도저히 설명할수가 없습니다.
:
: 왜 값이 그렇게 나오는 것인지 아시는 분은 설명좀 해주세요...ㅠ.ㅠ
:
: #include<stdio.h>
:
: int main(void)
: {
: printf("answer1 is the integer %d\n", 9/4);
: printf("answer2 is the real %f\n", 9/4);
: printf("answer3 is the integer %d\n", (double)(9/4));
: printf("answer4 is the real %f\n",(double)(9/4));
: printf("answer5 is the integer %d\n",(double)9/4);
: printf("answer6 is the real %f\n",(double)9/4);
: printf("answer7 is the integer %d\n",(double)9/(double)4);
: printf("answer8 is the real %f\n",(double)9/(double)4);
: printf("answer9 is the integer %d\n",17.0/3.0);
: printf("answer10 is the real %f\n",17.0/3.0);
: printf("answer11 is the integer %d\n",(int)(17.0/3.0));
: printf("answer12 is the real %f\n",(int)(17.0/3.0));
: printf("answer13 is the integer %d\n",(int)17.0/3.0);
: printf("answer14 is the real %f\n",(int)17.0/3.0);
: printf("answer15 is the integer %d\n",(int)17.0/(int)3.0);
: printf("answer16 is the real %f\n",(int)17.0/(int)3.0);
:
: return 0;
: }
:
: 출력값은
:
: 2
: 0.000000 <--문제의 부분
: 0 <--문제의 부분
: 2.000000
: 0 <--문제의 부분
: 2.250000
: 0 <--문제의 부분
: 2.250000
: -1431655765 <--문제의 부분
: 5.666667
: 5
: 0.000000 <--문제의 부분
: -1431655765 <--문제의 부분
: 5.666667
: 5
: 0.000000 <--문제의 부분
:
: 좋은 답변 부탁드립니다.
:
|