'Packing Structure'에 해당되는 글 1건

  1. 2007.11.23 프로토콜 헤더의 값 추출시 사용하는 struct word alignment설정하기
대부분의 프로토콜이나 화일들은 자신만의 특정 헤더 부분이 있다.
어디서부터 어디까지는 무슨 데이터이고... 이런 것들.

그런 헤더의 내용을 편리하게 가져오기 위해서 C/C++에서는 struct라는 구조체를 사용하여 불러오는 경우가 많다. 그렇게 하면 나중에 클래스의 어트리뷰트처럼 '구조체.필드이름'으로 접근할 수 있으니까.

그런데 여기서 한번 생각해 보아야 할 것이 과연 저런 구조체를 컴파일러는 어떻게 내부적으로 구현을 해 놓을까? 란 것이다.

컴퓨터 구조나 운영체제 시간에 메모리의 alignment라는 것을 들어 본 적이 컴공관련 학우라면 있을것이다.

워드단위로 메모리 입출력을 수행하는 중앙처리장치가 빠르게 값을 가져 올 수 있도록 하기 위해서 중앙처리장치의 처리단위 워드크기 경계로 맞추어 값을 배치하게 하는 것이 바로 'word alignment'이다.

프로토콜 헤더 정의를 잘 해서 프로그램에서 읽어온 값이 정작 쓰레기로 나오는 이유가 바로 저녀석 때문이다.

가령 CPU의 기본 처리 워드 크기가 32비트 ( 32bit CPU이라면... ) 일 경우 4바이트가 한 워드가 된다.

이러한 상황에서 비트맵파일의 헤더부분인 아래의 구조체는

typedef unsigned short WORD;
typedef unsigned int DWORD;

typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 'BM'이라는 identifier를 가짐.
DWORD bfSize; // 바이트단위 전체 파일크기
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits; // 파일의 첫위치에서 영상데이터 까지의 거리
} BITMAPFILEHEADER;


에서 WORD는 2바이트이고 DWORD가 4바이트라고 할 경우 bfType가 2바이트이므로 워드 정렬을 위해서 2바이트가 더 삽입되어 빈공간이 추가된 후 bfSize가 위치하게 되므로

sizeof(BITMAPFILEHEADER) 를 하면 14를 예상하겠지만 실제 16이 나온다.
궁금하면 해보기 바란다. 물론 CPU의 기본 워드단위에 따라 어찌 다르게 나올지도 모른다.

결론적으로 위의 상황에서는 도저히 프로토콜 헤더를 구조체를 이용해서 읽어오는게 불가능해 진다.
이를 해결하기 위해 컴파일러에게 워드 정렬을 다르게 하라고 지시를 해야한다.

이를 하는 지시어가 #pragma pack() 이다.
C/C++의 Standard에는 들어가는 사항이 아니지만 대부분의 컴파일러에서 사용가능하다.
컴파일러마다 조금씩 다른 용법을 가지고 있겠지만, 기본적으로

#pragma pack() 은 원래의 컴파일러 기본 워드정렬로 돌아오는 지시어이고
#pragma pack(n) 을 사용하면 (n은 2의 거듭제곱수. 1,2,4,8...) 지정한 n바이트로 워드 정렬을 수행하게 된다.

위의 경우 #pragma pack(2)를 해야 중간에 빈 공간이 생기는 경우가 없어진다.

typedef unsigned short WORD;
typedef unsigned int DWORD;

#pragma pack(2)
typedef struct tagBITMAPFILEHEADER
{
WORD bfType; // 'BM'이라는 identifier를 가짐.
DWORD bfSize; // 바이트단위 전체 파일크기
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits; // 파일의 첫위치에서 영상데이터 까지의 거리
} BITMAPFILEHEADER;
#pragma pack()


나중에 구조체를 만들어서 헤더파일등을 import 할 경우 반드시 고려 해야 한다.

기타 플랫폼별 컴파일러별 pack() 지시어의 특이사항에 관련된 내용은 잘 알지 못해 올리지 않았다. 각 벤더별 메뉴얼을 참조하기 바란다.

"Structure Packing"로 검색해보면 관련된 많은 내용이 나온다.
Posted by trip2me
,