2006년 08월 28일 Posted title : [006]sizeof, _msize 두번째 시간
1.지난시간 문제 풀이
먼저 지난시간에 제출한 “sizeof, _msize를 이용하여 할당한 메모리의 범위를 초과하는 에러를 잡아내는 매크로 함수를 작성하시오.”의 문제를 풀면서 정리를 해보자. 문제가 어려운 것처럼 보이지만 이 문제는 배열을 참조하는 인덱스가 배열의 크기를 초과하는지를 체크하면 된다.

배열의 크기를 얻기 위해서는 stack 공간의 메모리의 경우, sizeof(array)/sizeof(array[0])으로 구할 수가 있다.
int array[100];
sizeof(array); //400(=sizeof(int)*100)
sizeof(array[0]); //4(=sizeof(int))
그러므로 sizeof(array)/sizeof(array[0])는 400/4=100으로 배열의 크기가 100임을 계산할 수 있다. 그럼 배열을 참조하는 인덱스가 100보다 작은지, 아닌지를 비교해서 배열 범위를 초과하는지를 확인할 수 있다.

#define STATIC_ARRYA_RANGE_CHECK(x, i) {
if(sizeof(x)/sizeof(x[0]) <= i) printf("정적배열 초과: %s-%d ", #x, i);
}

#include <malloc.h>
#define DYNAMIC_ARRAY_RANGE_CHECK(x, i) {
if(_msize(x)/sizeof(x[0]) <= i) printf("동적배열 초과: %s-%d ", #x, i);
}

#define _DEBUG_ARRAY_CHECK
int narray[10];
int* nnew = new int[10];
for(int i=0; i<11; i++) {
...
#ifdef _DEBUG_ARRAY_CHECK
STATIC_ARRYA_RANGE_CHECK(narray, i);
DYNAMIC_ARRAY_RANGE_CHECK(nnew, i);
#endif
}
로 작성을 하면, i가 10일 때, 배열 범위 초과 에러를 발생하는 것을 잡을 수 있다. 일반적으로 버거의 대부분은 배열범위를 초과함으로써 많이 발생이 하고, 특히 Debug 모드에서는 동작을 하는데, Release 모드에서는 이상하게 동작을 하거나, 프로그램이 죽는 경우는 거의 100%가 배열의 범위를 초과한 경우라 생각을 하면 된다. 이때 위의 매크로를 이용하여 확인을 한다면 쉽게 문제점을 잡을 수도 있다.

2.sizeof가 keyword라는 의미는?
함수호출도 없고, 컴파일에 바로 숫자로 변환되어 적용된다. 이런 부분을 확인을 해보면(방법은 Debug모드에서, sizeof의 코드 라인에 break point를 걸고, 디버깅을 한 후, 메뉴에서 "View/Debug Windows/Disassembly"를 선택하면 assembly 코드를 볼 수 있다(다음에 디버깅에 대한 시간을 가지도록 하겠다).

20: int n;
21: int k = sizeof(n);
004010A8 mov dword ptr [ebp-8],4
을 보면 sizeof(n)이 숫자 4로 대체되어 있는 것을 볼 수 있다. 여기서 뭐 특별히 중요한 것은 없고, 디버깅 방법으로 Disassembly가 있다는 것만 알고 넘어가도록 하자.

3._msize의 다차원 배열의 경우?
int **new2d;
new2d = new int *[2];
new2d[0] = new int[5];
new2d[1] = new int[10];
printf("%d ", _msize(new2d)/sizeof(int)); //2
printf("%d ", _msize(new2d[0])/sizeof(int)); //5
printf("%d ", _msize(new2d[1])/sizeof(int)); //10
delete[] new2d[0];
delete[] new2d[1];
delete[] new2d;
위의 경우 2차원 배열에 대한 _msize 결과를 볼 수 있다. 여기서 뭐 특별히 중요한 것은 없고, 2차원 배열을 어떻게 생성하고 해제하는지만 알고 넘어가도록 하자. 2차원 배열은 두 가지 방법으로 생성, 해제할 수 있다.

한 가지 방법은 위에서 사용한 방법으로
int n=10;
int **new2d;
new2d = new int *[n];
for(i=0; i<n; i++) new2d[i] = new int[i+1];
for(i=0; i<n; i++) delete[] new2d[i];
delete[] new2d;

두 번째 방법은
int (*new2d)[100] = new int[n][100];
delete[] new2d;

이때 차이점은 첫 번째 방법은 두 번째 배열이 크기가 가변일 수 있고, 두 번째 방법은 두 번째 배열의 크기를 고정(위의 경우 100)으로 할 때 사용한다. 다차원 배열을 생성하는 방법은 꼭 기억을 해두는 것이 필요하다. 하지만 다차원배열은 특별한 경우가 아니면 사용하지 말고 1차원배열로 사용해라. 다차원, 1차원 둘 사이의 처리속도는 엄청나게 차이가 날 수 있다.

3.DLL에서의 heap manager
//DLL client(dll을 호출하는 부분, 보통 exe)
int* n = new int[10];
int size = _msize(n); //40
DllTest(n); //DLL 함수호출

//DLL
void DllTest(int* n) {
int* lp = new int[10];
int size = _msize(lp); //40
size = _msize(n); //error
}

DLL이 사용하는 heap가 DLL client(=exe)가 사용하는 heap이 틀리기 때문에 에러가 발생한다(동일한 Runtime 라이브러리를 사용하게 하여 같은 힙을 사용하게 하면 안 그럴 수도 있음. 또는 shared dll로 쓰는 경우 DLL client와 DLL의 heap manager가 같습니다. 그래서 DLL에서 new 한 메모리를 DLL client에서 지워도 문제가 없습니다. 여기에 대해서는 너무 상세한 내용이라 다음에 DLL과 관련한 내용에서 다시 한 번). 이때 알아둘 점은 서로 다른 heap에 대한 접근(n[0])은 허용되지만, 서로 다른 지역에서의 heap의 메모리 생성, 해제 및 _msize는 치명적인 에러를 발생하면서 허용하지 않는다는 것이다. 그래서 DLL에서 생성한 것은 DLL에서 해제를, 반대로 DLL client도 동일하다. 이는 간단하지만 DLL 프로그램을 작성하면서 매우 자주 발생하는 에러임을 명심해라. 따라서 DLL 에서 넘겨받은 힙의 메모리는 DLL 에 다시 넘겨 DLL 의 코드에서 해제 하도록 해야 한다.
예를 들자면...
int* GetMemory(int size);
void FreeMemory(int *data);
처럼 메모리를 얻어 오는 함수가 있으면 이 메모리를 다시 DLL 에 넘겨 해제 하는 함수도 함께 만들어 주어야 한다. 이는 single thread와 multi thread간에도 heap manager의 차이가 있다는 것을 알아두자. 즉, 자신의 Heap 공간이 아닌 공간에 대한 메모리 접근은 가능하지만, 생성, 해제 및 몇 가지 함수들에 대해서는 지원하지 않음을 명심하자.


Posted by sally | 2006/08/28 01:47 | programming | 트랙백 | 덧글(4)
트랙백 주소 : http://simple21.egloos.com/tb/2443594
☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]
Commented by X at 2006/08/28 03:05
날이 갈수록 감동이 밀려오는 명강의..
Commented by sally at 2006/08/28 10:41
X//X님 이후에 보니 HTML 오류가 있어서 수정했습니다. 이제 며칠만 있으면 볼 수 있겠네요. ^^
Commented by 바람 at 2006/08/29 00:39
내용이 너무 좋아요. 이런건 돈내고 팔아도 될텐데... 저 같은 경우에는 쓰레드1에서 예약한 메모리를 쓰레드2에서 해제하려고 에러가 났는데, 왜 안되는지 몰라서 오랬동안 고생한 기억이 있어요. 지금도 왜 안되는지는 몰라요. 그냥 안되는 것만 알고... ㅎㅎㅎ
Commented by 바람 at 2006/08/29 00:41
동영상이 너무 리얼해요. 연기가 아닌듯...

:         :

:

비공개 덧글

◀ 이전 페이지 다음 페이지 ▶



Get off my back
by sally
rss

skin by 에셈