신기한 visual c++ 6.0의 scanf의 float사용에 대한 버그

mandami의 이미지


//Code1
#include <stdio.h>
 
void main(){
    float f;
    scanf("%f",&f);
}

Visual C++ 6.0에서 위 코드를 사용하면 런타임 에러가 일어납니다.
%d나 %c등을 사용할때는 잘 동작하면서, %f만 사용하면 에러가 납니다.

정상적으로 사용하기 위해서는

//Code2
#include <stdio.h>
 
void main(){
    float f;
    scanf("%f",&f);
    printf("%f",&f);
}

이런식으로 printf를 사용해 줘야 합니다.

추측으로는 scanf에서 float형 처리할때 printf에 있는 모듈을 사용하는데, scanf만 사용하면 printf모듈이 컴파일돼어있지 않아 오류가 생기는 것아닐까, 합니다. 왜냐하면 Code2를 컴파일 한 후 Code1을 컴파일 하면, 똑같은 코드인데도 또 에러가 안나거든요. (Clean이나 rebuild all 해서 기존 목적 코드 다 없애면 다시 에러가 납니다.)

후배가 '형 컴파일 안되요'라고 물어봐서 처음 알았습니다. VC 6.0 쓴지 10년이 거의 다돼가는거 같은데, 지금까지 몰랐다는게 너무 신기하더군요.

chadr의 이미지

추측으로는 scanf에서 float형 처리할때 printf에 있는 모듈을 사용하는데, scanf만 사용하면 printf모듈이 컴파일돼어있지 않아 오류가 생기는 것아닐까, 합니다.
---

그런건 아닙니다. crt라이브러리를 사용할 때는 이미 컴파일된 라이브러리를 사용하므로 만약에 문제가 생긴다면 링크시 제대로 링크가 되지 않아서 그럴수도 있지만 링크가 안되는데 바이너리가 생성된다는 것 또한 말이 안됩니다.

원인은 초기화를 안한것에 있습니다.

float f = 1.0f;

으로 해보세요..
-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

-------------------------------------------------------------------------------
It's better to appear stupid and ask question than to be silent and remain stupid.

snowall의 이미지

초기화를 안해서 생기는 오류라면 printf 넣었다고 해서 오류가 안생기는 건 또한 이상한 것 같은데요?
뭐라고 설명을 해야 하나요?

--------------------------
snowall의 블로그입니다.
http://snowall.tistory.com

피할 수 있을때 즐겨라! http://melotopia.net/b

grassman의 이미지

만약 프로그램 내에서 명시적으로 부동 소숫점을 사용하는 부분이 존재하면 관련 모듈이 링크되는 겁니다. printf의 경우 부동 소숫점 모듈을 사용하므로 오류가 발생하지 않게 됩니다.

간단히 설명하면 Visual C++ 6.0은 부동 소숫점을 사용하는 코드를 컴파일 할 때 _fltused 라는 외부 함수 참조를 생성하게 됩니다. 이 함수는 scanf나 printf에서 사용하는 부동 소수점 모듈에 정의되어 있으며 링커는 라이브러리에서 부동 소숫점 모듈을 링크시키게 됩니다.

----------------------------------------------------
답글을 달고 나니 이미 먼저 답이 올라와 있군요. 중복이지만 지우지는 않겠습니다. :)

lifthrasiir의 이미지

VC++는 float을 파싱하는 라이브러리를 실행 파일에 포함시킬지 말지를 컴파일러가 결정합니다. 하지만 이 결정 과정이 그다지 좋지 않은 관계로, 위와 같은 상황에서 float 변수를 한 번도 (제 타입으로) 쓰지 않았다고 생각하기 때문에 해당 라이브러리를 빼 버립니다. 해결책은 물론 초기화를 하는 방법이고요.

VC++ 6.0 쓸 때 종종 만나던 문제였는데 (엄밀하게는 VC++의 동작이 사려깊지 못 한 탓이며 사용자의 잘못은 없습니다) 지금은 아닐 겁니다. MS에도 페이지가 있네요. (__fltused 심볼을 강제로 만드는 방법도 있는 것 같습니다만.)

Hyun의 이미지

그래도 초기화 하니깐 에러는 없네요.
개판(?)이군요. 이런걸 10년이나 사용해왔다니...
그나저나 %f는 double형 아닌가요?


cppig1995의 이미지

원형이 제공되지 않거나 가변 개수의 인자를 가진 함수의 경우 float는 double로 확장되나(printf)
float *는 double *로 확장되지 않기 때문에(scanf) %f는 float, %lf는 double입니다.
참고로, printf나 scanf나 long double은 %Lf입니다.



한말글 프로그래밍 언어 "열정" http://me-lang.wo.tc

Real programmers /* don't */ comment their code.
If it was hard to write, it should be /* hard to */ read.