어떤 바이너리 파일의 헤더를 구조체로 만들고 싶습니다.
그런데 어떤 이유때문에 꼭 256 바이트로 만들고 싶네요.
헤더의 항목은 작업하다 보면 여러개 추가될 것입니다.
이러면 보통 다음과 같이 합니다.
편의상 다음과 같은 의사 명령으로 1바이트 메모리 경계를 쓴다고 합시다.
디폴트로는 4바이트 메모리 경계인거는 다 아시죠.
#pragma pack(1)
typedef struct tagTHead
{
char IntroMsg[41];
int Count;
char Reserved[256 - 45];
} THead;
처음에는 레코드 갯수만 저장하는 Count 변수와 파일의 신원을 나타내는 정보 메시지가 들어가는 두개의 항목으로만
구성합니다. 하지만 나중에 항목을 수십개로 늘일 것입니다.
256 바이트에 꼭 맞추려면 위 두 항목의 사이즈를 256 바이트에서 빼서 계산해야 겠죠.
보통 이렇게 합니다.
그런데 빈번히 항목이 늘어나면 이거 계산하는거 귀잖습니다.
항목이 10개 이상만 넘어가도 그거 계산하려면 .... 계산기 꺼내야 함다.
혹 잘못 계산이라도 하면... 도움이 안되는 친구인 제길슨을 찾게 되죠.
이 계산을 컴파일러에게 맡기는 방법은 없을까요?
다음과 같은 offsetof 를 응용한 트릭으로 이를 해결할 수 있습니다.
#pragma pack(1)
typedef struct tagTHead
{
char IntroMsg[41];
int Count;
char reserved;
char Reserved[256 - offsetof(tagTHead, reserved) - 1];
} THead;
#pragma pack()
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Caption = sizeof(THead);
}
//---------------------------------------------------------------------------
빈 영역을 위한 Reserved 영역을 가르키는 항목이 이렇게 변했죠.
char Reserved[256 - offsetof(tagTHead, reserved) - 1];
생각같아서는
char Reserved[256 - offsetof(tagTHead, Reserved)];
로 하고 싶은데 이는 문법에서 허용하지 않습니다.
Reserved 가 아직 생성되지 않은 시점이라는 이유 때문입니다.
그래서 임시 변수 reserved 를 위에 적어주고 이 변수의 크기인 1을 빼주는 방법을 쓰면 됩니다.
그러면 이제 항목이 아무리 많이 늘어나도 항상 헤더 구조체의 크기는 256바이트를 일정하게 유지하게 됩니다.
예제는 1바이트 메모리 경계 상태를 대상으로 한 것인데
디폴트인 4바이트 경계를 가지는 경우는
char reserved;
가 4바이트 메모리를 차지하므로
char Reserved[256 - offsetof(tagTHead, reserved) - 4];
를 해줘야 한다는 것만 기억하면 됩니다.
확인해 보면 원하는 사이즈가 화면에 찍힙니다. ^^;
깜빡했었는데
이건 union을 써서 더 쉽게 해결하는 방법이 있고 이게 경우에 따라서는 좀 더 바람직합니다.
typedef union
{
struct
{
char IntroMsg[41];
int Count;
};
char Reserved[256];
} THead;
|
멤버로 클래스가 된다면
char reserved;
char Reserved[256 - offsetof(tagTHead, reserved) - 1];
와 같은 방식이
정말 유용하게 사용될 수 있습니다.