Create TOC

2002년 8월 20일

Visual C++ 6.0 버그

variable scope 버그

c++ spec을 지키지 않습니다.

for (int i = 0; i < 10; i++)
{
	; // nop
}

cout << i << endl;

이런 코드가 있을때 c++ spec 상 변수 ifor 범위 안에서만 유효해야 합니다. 따라서 cout 부분에서 에러가 발생해야 합니다.
하지만 VC 에서는 선언된 이후 계속 유효한 상태로 남아있습니다.

이 때문에 코드 이식성을 높이기 위해 위와 같은 문법을 사용할 수 없습니다.

기본 최적화에 따른 부동 소수점 연산 오류

아래 내용은 sleek에서 논의되었던 내용을 정리한것임.


다음과 같은 소스가 있습니다.

#include <stdio.h>

int main(int argc, char* argv[])
{
	float a = 0.433f;
	float b = a*1000.0f;
	int c = (int)b;

	printf("value %d \n",c);
	return 0;
}

이것을 실행해보면 432 가 나옵니다(VC++ 6.0 SP3, 4, 5 에서 확인함. gcc 에서는 433으로 잘 나옴).

반면

c = (int)(0.433 * 1000.0);

로 바꾸면 433으로 잘 나옵니다.

그리고 위의 소스를 다음과 같이 바꾸어도 433 이 잘 나옵니다.

#include <stdio.h>

int main(int argc, char* argv[])
{
	float a = 0.433f;
	float b = a*1000;

	float temp = 0.0f; // 쓸데없는 변수
	temp /= 100.0f;    // 쓸데없는 연산

	int c = (int)b;


	printf("value %d \
",c);
	return 0;
}

이렇게 되는 이유가 FPU 오차에 최적화 문제가 겹쳐서 발생되는 문제입니다.

float a = 0.433f;
float b = a*1000;
int c = (int)b;

여기서 a*1000는 FPU 레지스터에는 4.32999...e+0002 로 값이 나오는데, 이게 실제 메모리 b로 가면 4.33300..e+0002으로 라운딩이 됩니다.

근데.. 다음줄 c=(int)b;를 계산하려고 보니 b의 값이 아직 레지스터에 남아 있으니 4.3299...e+0002 를 가져다 계산하고 (int)변환은 라운딩 없이 무조건 잘라버리니까 결과는 432가 나오는데.. 즉 이건 c=(int)(a*1000); 과 동일한 값이 됩니다.

하지만 c=(int)b; 를 계산하기 전에 다른 코드가 있다면, 레지스터에 b를 다시 로드해야 되므로 메모리 b에 저장된 4.333000..e+0002를 먼저 FPU 레지스터에 불러들이고, 결과는 433이 나오게 됩니다.

정리해보면..

float a = 0.433f;
float b = a*1000;
int c = (int)b; // 이건 432
c= (int)b; // 이건 433
c= (int)(a*1000); // 이건 432
c= (int)b; // 이건 433

결국 Register에 있는 내용과 실제 메모리에 있는 내용이 다르면 당연히 메모리에 있는걸 읽어 와야 되는데 VC의 옵티마이저가 이걸 잘못 생각해서 errornous한 code 라고 생각하는 것 같습니다.

결국 MSDN 에 /Op 옵션을 사용하라고 나와있습니다.

PRB: Use /Op to Avoid Loss of Precision from Optimization

ps) VC.NET 에서는 이런 문제가 발생하지 않습니다 :)

Class view의 버그

아래 코드를 입력하고 class view 에서 확인해 보면 몇몇 함수는 제대로 표시되지 못합니다.

void a(int a, int b, int c);
void b(int a, int b = 1, int c = 1);
void c(int a, int b = 1, BOOL c = 1);
void d(int a, BOOL b = 1, BOOL c = 1);
void e(int a, BOOL b = 1, HKEY c = 1);