-- 이 글은 과거 테스트의 경험의 기억을 되살려 쓴 글이므로 오류 및 장비의 특성 compile등에 따라 다른 결과가 다를 수 있습니다. 아래의 테스트 환경은 UNIX서버 HP-UX에서 테스트 된 경우 입니다.
구조체 SIZE계산
pack 는 구조체에서 확정영역을 잡아놓고 사용하는 경우. 이 확장여역을 잘라서 사용할때 pack크기를 정해놓으면 편리하게 SIZE를 계산 할 수 있을 것 같다.
Ex)
struct st1 {
long cust_num;
char cust_nm[50+1];
int cust_age;
char cust_tel_no[20+1]
};
이런 구조체를 잡은경우 pack이 8이 기본값이라고 했을때
long cust_num : 8byte
char cust_nm[50+1] : 51byte이나 8의 배수의 근사값인 56 bype를 차지하게 된다.
이때 남아있는 byte 즉 56 - 51 = 5byte는 이어지는 변수고 char인 경우에는 나누에 쓸수 있으나 그렇지 않은 경우 (int/long등의 type)에는 사용하지 않다 다음 8byte로 넘어가게 된다.
int cust_age : 4byte 이가 pack이 8이므로 8byte를 차지함
char cust_tel_no[20+1] : 마지막 char인 경우 그냥 있는 그대로를 잡게 된다. 21byte 그러나 다음에 int/long등의 type일 경우 24byte를 차지하고 다음 int/long의 크기를 더하면 된다.
따라서 해당 구조체의 총 SIZE는 pack 8 인 경우
8 + 56 + 8 + 21 = 93이 된다. (확인안해봤습니다. 죄송.. 아마 맞을거임)
이 같은 현상은 메모리 정렬의 크기 때문인것으로 보인다. 전에는 cpu에서 처리하는 word단위 크기로 정렬된다고 생각했는데
pragma의 pack지지자를 보니 이값 때문으로 생각된다.
구조체의 SIZE계산은 좀 애매하기 때문에 꼭 sizeof문으로 크기를 점검하는 것을 권장한다.
그리고 마지막으로 필자가 이 같은 구조체의 SIZE계산을 하게 되었는지 설명하자면
위에서 언급했듯이 구조체의 마지막 또는 중간에 확장 영역을 잡아놓고 사용하고 싶기 때문이다.
예를 들어 아래와 같은 구조체의 경우 중간에 2개 마지막에 1개의 확장영역이 있다.
이 같은 확장영역이 필요경우는 프로젝트가 끝나가 업무요건이 발생하여 특정 항목을 추가해 주어야 하나
이같은 항목의 추가로 인한 전체 compile을 피하고 싶은 경우에 사용된다.
reserved라는 확장영역을 사용하려는 type의 크기만큼 잘라내어 사용할 경우 전체 구조체의 size는 변함이 없기
때문에 다른 곳에는 영향이 없고 사용하려는 일부 서비스/라이브러리 만을 새로이 컴파일 하게 되면
전체적은 영향도 없이 일부기능 추가 및 개선이 가능하다. 대형프로젝트의 경우 일괄적은 compile자체가 커다란 리스크이
부담이 되는 작업일 수 있다. 따라서 이같은 확장영역(reserved)영역을 설정해 놓으므로서 만일에 생길 수 있는
업무추가 요건이나 변경사항에 대비할 수 있게 되는 것이다. 이때 구조체의 SIZE계산이 필요한 것이며, 메모리 맵이 틀어지지 않도록 신중한 수정이 필요하다.
pack size를 8이 아닌 4, 2, 1을 사용할 경우 이 같은 계산이 좀 더 편해질 것으로 생각되나 테스트 해보지는 못했다.
※필수적으로 생각해야 할 규칙 pack 8기준(pack의 size가 4,2,1 경우 다른 결과를 낼 것이다.)
1. int와 char는 영역은 합쳐지지 않는다.
Ex1)
struct st1{
int i_num; /* 4byte */
char buff[4]; /* 4byte */
};
위의 구조체의 크기는 4+4 = 8 byte 일 것 같으나
pack 8에서 int가 사용하고 남은 공간 4byte는 char에서 사용하지 못한다.
따라서 이같은 경우에는 8 + 4 = 12byte가 된다.
Ex2)
struct st1{
char buff[4]; /* 4byte */
int i_num; /* 4byte */
};
이같은 경우 buff는 4byte만 사용했으나 int의 경우 공유가 안되므로
8 + 8 = 16이 된다.
2. char와 char는 남은 공간을 사용할 수 있다.
struct st1{
char buff1[4]; /* 4byte */
char buff2[4]; /* 4byte */
};
위의 구조체의 크기는 4+4 = 8 byte 이 된다.
3. 마지막에 char가 아닌 이외의 type인 경우 8byte를 전부 점유한다.
1번에서의 Ex1와 Ex2와의 차이에서 보면 마지막이 char이냐 int이냐에 따라
크기가 차이나는 것을 확인 할 수 있다. 따라서 확장영역은 주로 중간 보다는 마지막에 크기를 선택하여
잡아주는 것이 좋다.
struct PfmLinkExtInf {
char link_code[ LEN_LINK_CODE_EXT + 1 ]; /* 연동코드 */
PfmCoreHeaderStr pfmCoreHeaderStr; /* CORE Header */
PfmEaiHeaderStr pfmEaiHeaderStr; /* EAI Header */
char reserved[74]; /* 예비영역 */
/* 강제 호출 interface 서비스명-장애관리에 따르지 않음 */
char svcnm[ MAX_LEN_SVC_NAME + 1 ]; /* 서비스명 */
long call_seq_reset_flag; /* 외부system 호출 sequence 초기화 flag */
char filler[ 14 + 1];
char app_db_key[ LEN_APP_DB_KEY + 1 ]; /* 업무 DB Key */
char bef_global_id[LEN_GLOBAL_ID+1]; /* 취소정정 gid */
long timeout_reset_flag; /* timeout초 clear flag 0:default 1: clear */
long bypass_msg_type; /* 0: data전문, 1: full전문 */
long async_nolog_type; /* 0: default, 1: async 연동로그 안 쌓음 */
void *svc_hdr_ptr; /* service header structure pointer */
void *in_str_ptr; /* input structure pointer */
long in_str_len; /* 입력전문의 길이 */
void *out_str_ptr; /* output structure pointer */
long out_str_len; /* 출력전문의 길이 */
char bat_shell_name[LEN_BAT_SHELL_NAME+1]; /* Batch shell name */
char bat_args[LEN_BAT_ARGS+1]; /* Batch shell arguments */
/* 수신시스템ID */
char rms_sysid[LEN_PFM_LINK_EXT_PS001OUT_RMS_SYSID+1];
/* EAI 연동 복수시스템연동인터페이스 */
char multi_sys_link_inf[LEN_MULTI_SYS_LINK_INF+1 ];
char reserved1[707]; /* reserved area1: 2K */
PfmMsgInf err_msg; /* link result error message */
PfmMsgInf nrm_msg; /* link result normal message */
char link_global_id[LEN_GLOBAL_ID+1]; /* link gid */
long cd; /* connect descriptor */
PfmDbiopfm_link_ext_ps001Output pfm_link_ext; /* 연동파라미터 */
long err_type; /* 에러 type:내부연동에러 1, core에러 2 */
char reserved2[813]; /* reserved area2: 2080Byte - total 4128 */
};
typedef struct PfmLinkExtInf PfmLinkExtInf;