반응형
출처 : http://ariswear.com/new_blog/312

[1byte alignment 이야기]

작성: 이홍기 <orinmir _at_ chonga _dot_ pe _dot_ kr> http://chonga.pe.kr
작성일: 2001년 8월 2일

1. 개요

  온라인 게임이나 네트웍 프로그램을 작성하는 중에, 우리가 패킷단위를 structure로

정의해 memcpy등을 하려고 할 때, 기본 memory alignment 방식이 4byte(인텔 32bit기준)이므로

실제로 structure 정의를 아래와 같이 하면

  struct pkt {
  int a;
  char b;
  };

분명 5byte만큼만 정의했지만, 기본 alignment는 4byte 씩이므로 sizeof는 8이 나온다.

memcpy를 해서 5byte 크기의 버퍼에다 넣어주면 밀려버린 상태로 들어가게 될 것이다.

메모리의 효율적인 할당 방식으로 들어가는 것이 기본으로 설정되므로 우리가

원하는 결과를 얻기 힘들다.

이 때에는 1byte alignment를 해주어야하며, 기본 alignment가 아닌 경우

전체적인 수행 속도에도 영향을 미친다는 이야기를 들은 적이 있긴하다..

하지만 어쩌랴.. 정확한 패킷 처리를 위해선 피하갈 수 없는 산이다.


그렇다면 alignment란 정녕 무엇인가? 궁금한 사람은 아래를 참조하고

이도저도 귀찮은 사람은 사용방법으로 넘어가보자.

http://www.cs.umd.edu/class/fall1998/cmsc411/projects/outer/memory/align.htm


2. 사용방법


a) 전체에 걸기

   피치 못할 사정에 의해 컴파일할 때에 아예 전체를 1byte alignment를 해주어야 한다면 어떻게
   해야할까?

   gcc를 예를 들면 -fpack-struct 쪽을 참고해주면 되겠다.
   (이 사이트 주목 http://gcc.gnu.org/ml/gcc/1999-03/msg00428.html)

위 사이트를 방문해 보면 알겠지만 아래와 같은 문제점이 있다고 한다.

     If the library and the rest of the application don't share *any*
     structures, it might work. This means that you can't do the following
     things in the library:
       - use stdio (e.g. printf)
       - use system calls that take structures (ioctl(2), stat(2))
       - use setjmp

   공유 라이브러리는 1byte alignment를 고려하지 않는 경우가 있기 때문에도
   전체 scope으로 1byte alignment를 하면 굉장히 위험하다고 한다.

   또한 이유없이 SIGSEGV를 받고 죽어버릴 수도 있다.


b) #pragma pack 이용하여 범위 지정

   보통 1byte alignment를 하므로

   #pragma pack(1)로 시작해주고 #pragma pack() 으로 끝내면서 기본값으로
   반환해준다.

   #pragma pack(4)이라고 끝내어도 되겠지만., 시스템이나 아키텍쳐마다

   다를 수 있으므로 pack()가 현실적이다.

   예를 들자면

   #pragma pack(1)
   struct a { int i; char j; };
   struct b { char a[9]; unsigned short b; };   
   #pragma pack()
   struct c { char a[9]; unsigned short b; };   

   위는 sizeof(struct a)는 5이고, sizeof(struct b)는 11이다.
   하지만 sizeof(struct c)는 16이 나올 것이다.


c) __attribute__((packed)) 를 이용하여 개별적으로 지정

   각각의 structure나 class에 걸어줄 수가 있다.

   이 방법을 가장 추천한다.

   struct __attribute__((packed)) A {
    char c;
    int  i;
   } a ;

   struct B {
    char c;
    int  i;
   } b ;

   결과를 보자면 sizeof (a) 는 5이다.  sizeof (b) 는 8이다.

**주의사항인데 아래와 같이 structure를 포함한 structure나 class에서

   class __attribute__((packed)) A {
   public:
   struct mystruct  {
   char c;
   int i;
   } st;
   public:
   A() { }
   ~A() { }
   };

   위에서 mystruct는 4byte align이 된다. 실수하기 쉬운 부분이다.
아래와 같이 또 선언해줘야한다.

   class __attribute__((packed)) A {
   public:
   struct __attribute__((packed)) mystruct  {
   char c;
   int i;
   } st;
   public:
   A() { }
   ~A() { }
   };

   또 한가지가 있는데 아래와 같이 소멸자에 virtual을 선언한 경우, vptr도
4byte(인텔 32bit 기준)을 먹는다. --;

   class __attribute__((packed)) A {
   public:
   struct __attribute__((packed)) mystruct  {
   char c;
   int i;
   public:
   A() { }
   virtual ~A() { }
   };



3. 기타

  이 예제는 모두 gcc에서 테스트되었다.


반응형

'C & C++ 관련' 카테고리의 다른 글

C++ dlopen mini HOWTO  (0) 2010.10.29
explicit 키워드  (0) 2010.03.30
How do I call a C++ function from C?  (0) 2010.03.22
Posted by Real_G