logo

한국어

[VC] #pragma pack

관리자 2010.04.17 23:11 조회 수 : 58

메모리 패킹


1.요약

#pragma pack을 이용하여 메모리를 특정 align으로 packing할 수 있다.


2.본문

데브피아에 다음과 같은 팁이 올라왔다.

-----------------------------------------------------------------

구조체 / 공용체 도는 클래스를 바이트 스트림으로 변화시켜야한다면 메모리를 패킹하자.
- 사용하는 구조체 또는 공용체 / 클래스를 바이트 스트림으로 변화시켜야한다면, 메모리를 1 바이트 정열을 시켜야 정확한 바이트 단위 크기를 갔습니다. 주로 통신 프로그램을 만드는 경우에 해당하겠군요

예 )
   
-----------------------------------------------------------------

그럼 왜 이런 방법을 사용해야하는지와 좀더 구체적인 용법을 알아보겠다.

먼저 alignment는 compiler에서 구조체/공용체 데이터를 처리하는 단위가 된다. 이것은 VC의 [Project Settings]의 C/C++탭의 Code Generation항목에서 조절 가능하다. 또한 컴파일러 옵션의 /Zp가 이러한 역활을 한다.

디폴트값은 8이다. 이것은 우리가 구조체를 만들면 8byte단위로 alignment가 정해진다는 의미이다.

다음과 같은 구조체가 있다.

typedef struct GTcpPacket 

{

char mark1[8];

int len;

}GTCPPACKET, FAR * LPGTCPPACKET, *PGTCPPACKET;

위 구조체의 크기를 계산해보면

GTcpPacket packet; 

int nAllSize = sizeof(packet);

int nSize1 = sizeof(packet.mark1);

TRACE("size:%d, %d\n", nAllSize, nSize1);

size:12, 8

구조체 전체의 크기가 12(8+4)이고 mark1의 크기가 8임을 알 수 있다.

typedef struct GTcpPacket 

{

char mark1[9];

int len;

}GTCPPACKET, FAR * LPGTCPPACKET, *PGTCPPACKET;

와 같이 mark1의 크기를 1byte 늘렸다.

결과를 출력해보면

size:16, 9

와 같이 된다. 이론적으로는 9+4 = 13되어야하겠지만 compiler의 alignmemnt의 영향으로 이러한 현상이 일어나는 것이다.

데이피아에 언급된 방법으로 alignment를 조절해보자.

#pragma pack(push,enter_byte_packing) 

#pragma pack(1)

typedef struct GTcpPacket

{

char mark1[9];

int len;

}GTCPPACKET, FAR * LPGTCPPACKET, *PGTCPPACKET;

#pragma pack(push,enter_byte_packing)

size:13, 9

이경우는 결과가 정상적으로 나왔다.

#pragma pack을 쓰지않고도 VC의 프로젝트 세팅에서 이러한 alignment를 조절할 수 있다고 앞서 설명했다. 그러나 이러한 방법은 프로젝트 전체에 걸처서 적용되기때문에 특정 구문/파일에만 적용할때는 데브피아에서 언급한 #pragma pack을 사용한다.

그런 #pragma pack의 용법을 좀더 구체적으로 알아보자.

프로토타입

#pragma pack( [ [ { push | pop}, ] [  identifier, ] ] [ n ] ) 
push, pop이 있는것이 특이할 것이다. 이것은 컴파이러 스텍을 이용함을 의미한다. 즉 뒤에 붙는 identifier 로 push한 이후의 컴파일러 옵션은 n으로 지정한 값을 적용받고 pop하면 지정된 옵션이 풀리게된다.

MSDN의 예제에 보면 이러한 방법으로 헤더파일 전체를 특정 alignment로 지정하는것을 볼 수 있는데 다음과 같다.

#pragma pack( push, before_include1 ) 

#include "include1.h"

#pragma pack( pop, before_include1 )

여기서 identifier는 그냥 구분자이므로 push때와 pop때에 일치되는것만 쓰면 어떤것이든 상관없다. 단... 중복해서 사용하지는 말기를...

출처 : http://blog.daum.net/sandwind/13423451