#pragma 매크로 중 pack에 관련된 내용을 정리하려 합니다. 해당 내용은 C언어 프로젝트에서 한 번쯤 살펴볼 수 있는 구문인데요, 어떤걸 의미하는지 정리해보고자 합니다.
[구문]
#pragma pack( [ show ] | [ push | pop ] [, identifier ] , n )
#pragma pack 은 위와 같은 구문으로 구성되어 있습니다. pack 이란 단어가 무슨 의미인지 아시나요?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #include <stdio.h> typedef struct { char a; int b; short c; } basic_s; #pragma pack(1) typedef struct { char a; int b; short c; } pack1_s; #pragma pack(2) typedef struct { char a; int b; short c; } pack2_s; #pragma pack(4) typedef struct { char a; int b; short c; } pack4_s; int main(int argc, char *argv[]) { printf("basic_s size : %lu\n", sizeof(basic_s)); printf("pack1_s size : %lu\n", sizeof(pack1_s)); printf("pack2_s size : %lu\n", sizeof(pack2_s)); printf("pack4_s size : %lu\n", sizeof(pack4_s)); return 0; } | cs |
위 예제를 실행시키면 아래와 같은 결과를 얻을 수 있습니다.
각 구조체 내부 구성은 char, int, short 순서로 동일한데 사이즈가 다르게 나타납니다!
linuxias@desktop:~/$ ./pack_basic
basic_s size : 12
pack1_s size : 7
pack2_s size : 8
pack4_s size : 12
이런 현상이 발생하는 이유가 뭘까요?
#Pragma Pack은 해당 구조체를 메모리에 배치할 때 어떻게 할 것인가를 결정해줍니다. 기본적으로 char(1byte), int(4byte), short(2byte)의 순서로 구조체에 선언하게 되면 아래와 같이 메모리가 잡히게 됩니다.
char (1byte) |
padding (3byte) |
int (4byte) |
short(2byte) |
padding 2(byte) |
기본적으로 각 요소에 대해 4byte를 기본으로 합니다. 만약 다음 자료형까지 4byte 내에 포함될 수 있다면 4byte 내에 포함된다는 의미입니다. 무슨말인즉 char, short, int의 순으로 정의되었다면 구조체의 크기는 8byte가 됩니다. char(1), short(2), padding(1), int(4) 순으로 메모리에 정렬될테니 말이죠.
#Pragma pack은 저러한 구조체의 정렬방식을 지정합니다.
#Pragma pack(1) => 1byte로 정렬
#Pragma pack(2) => 2byte로 정렬
#Pragma pack(4) => 4byte로 정렬
조금 이해 되시나요? 표로 더 살펴보죠.
#Pragma pack(1)은 1Byte 단위라고 했죠? 그럼 모든 자료형이 연속된다고 생각하시면 됩니다. 아래와 같은 구조가 되서 크기가 7이 됩니다.
char (1byte) |
int (4byte) |
short (2byte) |
다음 #Pragma pack(2)는 2Byte 단위 정렬이 됩니다. 그럼 제일 먼저 선언된 char 자료형은 뒤에 padding 1byte를 붙여 2 byte로 만들어 주겠죠? 아래와 같이 메모리가 할당되며 구조체의 크기는 8이됩니다.
char (1byte) |
padding (1byte) |
int (4byte) |
short(2byte) |
그럼 마지막으로 #Pragma pack(4)는 어떻게 될까요? 구조체 메모리 정렬 시 기본적으로 4Byte를 기반으로 한다고 앞에서 말씀드렸습니다. 그럼 처음 설명드렸던 내용과 동일하겠죠? 그래서 결과는 12 byte가 됩니다.
여기서 의문입니다. 이러한 구조체 메모리 정렬을 왜.. 사용하는 걸까요? 구조체의 바이트 패딩 문제는 여러 상황에서 문제가 될 수 있습니다. 예를 들어 CPU 레지스터를 읽는다고 해보죠. 레지스터에서 읽은 값을 구조체에 매핑하고자 합니다. 하지만, 읽은 값을 그대로 쓰기엔 바이트 패딩문제로 인해 정확하게 매핑이 되지 않는 문제가 할 수 있습니다. 그래서 정렬시켜주고 할 때도 사용하죠. 또는 네트워크를 이용한 통신을 지원할 시 각 단말 간 다른 메모리 구조나 바이트 패딩문제로 정확하게 메모리 할당이 되지 않는다고 생각해봅시다. 이런경우 바이트 패딩을 제외하고 모든 메모리가 순차적으로 정렬된 상태에서 보내게 되면 쉽게 받아 해석이 가능하겠죠.
그 외에도 여러가지 용도로 많이 사용됩니다. 한번 적용 가능한 곳에 찾아 적용해 보시면 좋을 것 같습니다.
push와 pop 등에 대해서는 나중에 다른 글로 따로 정리하겠습니다.
'Language > C,C++' 카테고리의 다른 글
표준출력에 텍스트 색상 입히기 (colorize printf format) (0) | 2018.10.09 |
---|---|
[macro] 안전한 형변환을 위한 Macro (0) | 2018.08.09 |
[C++] atomic_flag (0) | 2018.06.26 |
C언어 try-catch 흉내내기 (0) | 2018.03.19 |
[C언어] 실수형 MAX, MIN 값 (0) | 2017.11.05 |