1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <stdio.h> typedef struct { char a; char c; short d; char e; int b; } Test_Struct; int main() { Test_Struct str_t; printf("\n[STRUCT]\n"); printf("size=%d\n\n",sizeof(str_t)); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #include <stdio.h> typedef struct { char a; char b; char c; char d; int e; } Test_Struct; int main() { Test_Struct str_t; printf("\n[STRUCT]\n"); printf("size=%d\n\n",sizeof(str_t)); } |
char(1바이트) 4개 = 4바이트
int(4바이트) 1개 = 4바이트
= 총 8바이트
구조체 사이즈도 8바이트가 나왔다!
위의 코드와 아래 코드의 사이즈에서 왜 차이가 나는 것일까?
이유는 패딩비트가 추가되었기 때문이다. 몇몇 컴파일러는 구조체의 필드를 메모리에 위치시킬 때 중간에 빈 공간없이 이어서 할당하는 경우도 있지만, 대부분의 컴파일러는 성능향상을 위해 CPU가 접근하기 쉬운 위치에 필드를 배치한다. 그러다보니 중간에 빈 공간이 들어가게 되는데 이것을 패딩비트라고 부른다.
32bit CPU는 메모리에서 값을 읽어올 때 한 번에 32bit씩(4Byte)를 읽어온다. 그런데 레지스터가 읽는 블록의 경계에 걸쳐 멤버 변수가 생긴다면 메모리를 읽을 때 두 개의 블록을 읽는 문제가 발생한다.
예를 들면, 구조체 안에서 char a, int b 이런 식으로 4Byte 단위로 생성을 안 했을 때 문제가 발생한다. 만약 구조체 멤버 b변수에 접근하려고 하면 어떻게 될까?
구조체의 시작 주소에서 32bit를 읽어와도 멤버 b의 비트에 모두 접근 할 수 없다. 그래서 두 번 메모리를 읽어서 첫 번째 읽은 값에서 뒤의 24bit(char 8bit를 뺀 부분)와 두 번째 읽은 값에서 앞의 8bit를 합쳐서 멤버 b의 값을 구할 수 있다. 하지만!!!!! 한 번에 할 수 있는 일을 두 번에 걸쳐서 하는 것이기 때문에 성능저하가 발생한다.
그래서 대부분의 컴파일러는 CPU가 접근하기 쉬운 메모리 위치에 필드를 배치시켜서 패딩비트가 자동으로 들어가게 된다.
즉, char a, int b라고 선언한 부분에서는 멤버 변수 a와 b사이에는 3byte의 패딩 비트가 들어간 것이다. 이렇게 하면 메모리를 3바이트나 낭비하게 되지만 각 멤버에 접근할 때 한 번씩만 메모리를 읽으면 되기 때문에 성능저하가 발생하지 않는다.
하지만! #pragma pack(1) 이란 전처리어를 사용하면, 구조체 사이즈가 달라진다!
size=12는 pragma pack을 사용하기 전의 구조체 사이즈이고, size=9는 pragma pack을 사용했을 때의 구조체 사이즈이다.
char(1Byte) + short(2Byte) + short(2Byte) + int(4Byte) = 9Byte
하지만 pragma pack을 사용하기 전에는 char + short + padding bit = 4Byte,
short + padding bit = 4Byte,
int = 4Byte.... 그래서 12바이트가 나온 것이다.
'언어 > C' 카테고리의 다른 글
[CubeBite] File_Create_Write 함수 (0) | 2017.02.08 |
---|---|
[Tip] File I/O Error 다루는 법 (0) | 2016.11.05 |
비트필드 구조체 (0) | 2016.10.27 |
volatile 형한정어 (0) | 2016.10.19 |
scanf와 fgets 함수를 같이 사용하면서 나타나는 문제점 (0) | 2016.10.19 |