프로매퍼에서 제공하는 강력한 기능 중에 하나가 가변배열이다. 이 가변 배열용 api를 이용하면 포인터라는 어려운 개념을 알지 못하는 사람도 충분히 메모리를 동적 할당(alloc)할 수 있도록 해 준다. 그렇지만 아래에 기술되어 있는 내용 정도는 정확히 이해를 해 줘야 문제를 야기하지 않고 즐거운 코딩을 할 수 있다.
1. 정의
Varray 의 타입에 대하여 pfmVarray.h 속에 다음과 같이 미리 선언되어 있다.
#define pfmVarray(type) \
struct { \
long size; \
long count; \
type *data; \
}
따라서 가변배열 변수를 선언할 때는 다음과 같이 한다.
pfmVarray(sfee2105a_in_sub01) grid_id;
여기서 sfee2105a_in_sub01 은 타입이고 grid_id 는 변수명이다. 결국 위의 선언문장은 실제적으로는 다음과 같이 소스가 풀어지게 된다.
struct {
long size;
long count;
sfee2105a_in_sub01 *data;
} grid_id;
위의 풀어진 가변 배열의 실체를 머릿속에 기억하고 있다면 프로그램을 짤 때 혼란이 적을 것이다.
2. 샘플 코드
다음과 같은 샘플 예제를 작성하여 돌려 보았다.
mfeebiz_sfee2105a_in_sub01 sub;
mfeebiz_sfee2105a_in in;
PFM_DBG(" mfeebiz_sfee2105a_in = [%ld]", sizeof(mfeebiz_sfee2105a_in));
PFM_DBG(" mfeebiz_sfee2105a_in_sub01 = [%ld]", sizeof(mfeebiz_sfee2105a_in_sub01));
bzero( &in, sizeof(mfeebiz_sfee2105a_in));
PFM_DBG("Varray size = [%ld]", pfmVarraySize(in.grid_id));
PFM_DBG("Varray count = [%ld]", pfmVarrayCount(in.grid_id));
PFM_DBG("Varray Buffer Size = [%ld]", pfmVarrayBufferSize(in.grid_id));
PFM_DBG("Varray Structure Size = [%ld]", pfmVarrayStructSize(in.grid_id));
for ( int ix = 0; ix < 102; ix++ ) {
PFM_DBG("add [%d] =======", ix);
pfmVarrayAppend( in.grid_id, &sub );
PFM_DBG("Varray size = [%ld]", pfmVarraySize(in.grid_id));
PFM_DBG("Varray count = [%ld]", pfmVarrayCount(in.grid_id));
PFM_DBG("Varray Buffer Size = [%ld]", pfmVarrayBufferSize(in.grid_id));
PFM_DBG("Varray Structure Size = [%ld]", pfmVarrayStructSize(in.grid_id));
}
3. 수행결과
0153] mfeebiz_sfee2105a_in = [88]
0154] mfeebiz_sfee2105a_in_sub01 = [336]
0157] Varray size = [0]
0158] Varray count = [0]
0159] Varray Buffer Size = [0]
0160] Varray Structure Size = [336]
0163] add [0] =======
0166] Varray size = [100]
0167] Varray count = [1]
0168] Varray Buffer Size = [33600]
0169] Varray Structure Size = [336]
0163] add [1] =======
0166] Varray size = [100]
0167] Varray count = [2]
0168] Varray Buffer Size = [33600]
0169] Varray Structure Size = [336]
중간생략 --
0163] add [99] =======
0166] Varray size = [100]
0167] Varray count = [100]
0168] Varray Buffer Size = [33600]
0169] Varray Structure Size = [336]
0163] add [100] =======
0166] Varray size = [202]
0167] Varray count = [101]
0168] Varray Buffer Size = [67872]
0169] Varray Structure Size = [336]
0163] add [101] =======
0166] Varray size = [202]
0167] Varray count = [102]
0168] Varray Buffer Size = [67872]
0169] Varray Structure Size = [336]
4. 결론
결론 초기에 추가할 수 있는 한계치로 100 을 설정해 놓고 있다가 100개를 초과하게 되면 size는 다시 자동 늘려준다. 메모리도 구조체의 사이즈 * size 만큼의 메모리를 미리 확보해 놓았다가 사이즈를 넘어서면 다시 추가로 더 늘려서 allocate 해 놓게 된다. 이 100 이라는 초기 배열의 개수를 정하는 알고리즘은 이 함수를 개발한 사람이 알고 있겠지만 늘상 100 으로 초기설정되는 것은 아니고 그 type 에 따라 달라지는 것을 보았다.
반면에 count 값은 몇번을 append 했는지의 회수 정보이다. 따라서 영원히 count 가 size 를 초과할 수는 없게된다.
특정 회수번지의 값을 찍어 보고자 한다면 다음과 같이 할 수 있다. 예를 들어 10번째의 것을 찍어본다면
PFM_DBG(" name = [%s]", grid_id.data[9].name );
5. 또 다른 예제
pfmVarray(long) vcnt;
long *cnt;
long *num;
bzero(&vcnt, sizeof(vcnt));
cnt = pfmVarrayAlloc(vcnt, 10); /* 10개의 저장 공간 확보 */
cnt[1] = 1; /* 두번째 배열에 값을 1 세팅함 */
PFM_DBG("sizeof(vcnt) = [%ld]", sizeof(vcnt));
PFM_DBG("Varray size = [%ld]", pfmVarraySize(vcnt));
PFM_DBG("Varray count = [%ld]", pfmVarrayCount(vcnt));
PFM_DBG("Varray Buffer Size = [%ld]", pfmVarrayBufferSize(vcnt));
PFM_DBG("Varray Structure Size = [%ld]", pfmVarrayStructSize(vcnt));
PFM_DBG("==== 출력 ====" );
PFM_DBG("vcnt.data[1] = [%ld]", vcnt.data[1] );
PFM_DBG("pfmVarrayGet(vcnt, 1) = [%p]", (long *)pfmVarrayGet(vcnt, 1));
PFM_DBG("pfmVarrayElementAt(vcnt,1) = [%p]", (long *)pfmVarrayElementAt(vcnt, 1));
/*좀 더 어렵게 출력해 보는 방법으로 */
PFM_DBG("*(_num = pfmVarrayGet(vcnt, 1)) = [%ld]", *(num=pfmVarrayGet(vcnt, 1)));
6. 실행결과
|
7. 결론
pfmVarrayGet() 과 pfmVarrayElementAt() 함수는 동일한 포인터를 리턴해 준다는 것을 기억해야 한다. 가변 배열 변수는 궁극적으로 스트럭쳐 라는 것을 기억한다면 이 변수의 초기화는 bzero(&vcnt, sizeof(vcnt)); 를 사용하거나 memset(&vcnt, 0x00, sizeof(vcnt)); 를 사용할 수 있다.
8. 위험한 상상
pfmVarrayAppend 로 값을 append 세팅해 놓은 다음 bzero(&vcnt, sizeof(vcnt)); 와 같이 초기화하는 것은 의미가 없으며 매우 위험하다. sizeof(vcnt) 의 값은 append 하기 전 선언당시의 구조체사이즈(24byte) 이기 때문이다. 추가로 할당된 메모리는 초기화되지 않게 된다. 심지어 vcnt.data 가 가지고 있던 포인터까지 지워버렸기 때문에 append 될 때 추가 할당된 메모리는 포인터를 잃어 버려서 free시킬 수도 없는 dangliing 상태에 놓이게 되며 memory leak 의 주요 원인이 된다.
또다른 예로서 memcpy( &another, &vcnt, sizeof(vcnt)); 뭐 이런식으로 sizeof를 사용했을 때는 딸랑 24byte 만 copy 된다는 것을 기억해야 한다. 왜냐면 Varray 변수의 사이즈는 24 byte ( long 변수 size와 count 로 2개, pointer 변수 data 로 1개 도합 8byte * 3 = 24 byte ) 이기 때문이다.
9. 가변배열의 메모리 해제
가변 배열에 구조체를 계속 append하다가 오류가 발생될 경우 PFM_TRY를 타고 프로그램이 종료된다. 프레임웍이 종료될 때 가변배열변수는 자동 해제를 시키지만 프레임웍의 시스템후처리를 지나기 전에 반복적으로 가변배열을 사용하는 모듈을 호출하게 되면 미처 해제되지 못한 가변배열이 쌓여서 시스템의 힙메모리가 부족해 지는 사태를 초래할 수 있다. 따라서 가변배열을 사용하는 모듈은 오류종료될 경우에는 아래와 같이 메모리를 직접 해제시키고 나가도록 코딩을 기술해 주면 시스템 안정성에 도움이 된다.
/*오류발생시 가변배열을 free 시켜서 메모리 leakage 방지 */
pfmVarrayFree(OUTPUT->grid_id);
/* 또한 그리드에 append한 개수를 관리하는 변수가 따로 있다면 이 값도 초기화 */
OUTPUT->rept_ncnt = 0;
출처 : http://pangate.com/66
'프로그램언어 > Proframe' 카테고리의 다른 글
프로프레임 PFM_TRY 에 대한 이해 (0) | 2010.08.27 |
---|---|
프로프레임 소스 문자열 변환 프로그램 (0) | 2010.08.27 |
제우스 동작 멈춤 상태 (0) | 2010.08.27 |
DBIO 소스 gen 수정 요청합니다. (0) | 2010.08.27 |
code inspection (0) | 2010.08.27 |