1byte alignment 이야기 [struct 패딩에대한..]
C & C++ 관련 :
2010. 3. 31. 07:34
반응형
출처 : 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에서 테스트되었다.
[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 |