struct map_form
{
char sBsnsDate[8];
char sCount[4];
struct ITEM item[1000]; /* ITEM의 크기는 88 */
};
위의 구조체 크기는 88012 일거라고 생각했다. 하지만 sizeof(struct map_form) 결과, 88016 이 나왔다.
메모리 할당 문제이다. 아래에 자세한 설명이 있다.
구조체가 메모리에 할당될 때는 일정한 규칙을 가진다. 일반적으로 우리가 생각하기에 어떤 구조체가 메모리에 할당될 때
구조체의 첫 번째 멤버부터 순서대로 메모리에 차곡차곡 쌓여간다고 생각한다.
구조체의 첫 번째 멤버부터 순서대로 메모리에 차곡차곡 쌓여간다고 생각한다.
예를 들어 다음과 같은 구조체가 있다고 생각해보자.
struct StructA{
char a;
int b;
char c;
int d;
};
일반적으로 생각하기에 위의 구조체가 메모리에 할당되는 그림은 다음과 같다
[char a 1byte][int b 4byte][char c 1byte][int d 4byte]
그런데 문제는 이렇게 해서 전체 10바이트가 할당이 될 거라고 생각하면 오산 이라는 것이다.
실제로 메모리에 할당되는 그림은 다음과 같다.
[char a 1byte][padding 3byte][int b 4byte][char c 1byte][padding 3byte][int d 4byte]
우선 눈에 들어오는 부분은 중간 중간에 padding데이터가 끼어있다는 것이다.
좀더 자세히 살펴보면 메모리를 4바이트씩 묶을 수 있다는 사실을 발견할 수 있다. 그럼 반대로 4바이트씩 떼어서 보자.
[char a 1byte, padding 3byte] [int b 4byte] [char c 1byte, padding 3byte] [int d 4byte]
자 이렇게 보면 4바이트씩 데이터가 구분되어 있다는 것 이다. 이런 식으로 메모리를 사용하는 이유는 데이터를 읽고 쓸 때 보다 효율적으로 사용하기 위해서다.
메모리에 할당할 때 4바이트씩 그 4바이트 안에 들어가지 않으면 나머지는 비워두고 다음 4바이트가 되는 주소에 넣어버리는 것이다. 때문에 위에서 보이는 것처럼 char a 다음에 int b가 바로 오지 않고 padding이 3바이트가 있는 것이다.
이렇게 구조체가 메모리에 할당될 때 일정한 규칙이 있는데,
1. 구조체의 멤버들 중에 가장 큰 데이터형을 찾는다.
-> int형이 가장 큰 데이터형 이므로 4byte
2. 그 데이터형의 크기와 맞게 메모리를 쪼갠다.
-> 4byte씩 메모리를 나눈다. [4byte][4byte][4byte][4byte][4byte]
3. 멤버들을 차곡차곡 쌓아 넣는다.
a. char a를 넣는다.
[char a]
b. int b를 넣어야 되는데 char a가 들어가 있는 곳에는 3바이트밖에 남아있지 않으므로 다음 메모리에 넣는다.
[char a 1byte, padding 3byte][int b 4byte]
c. char c를 넣는다.
[char a 1byte, padding 3byte][int b 4byte][char c 1byte]
d. int d를 넣어야 되는데 char c가 들어가 있는 곳에는 3바이트밖에 남아있지 않으므로 다음 메모리에 넣는다.
[char a 1byte, padding 3byte][int b 4byte][char c 1byte, padding 3byte][int d 4byte]
이런 식으로 할당되는 것이다.
그런데 padding으로 채워진 부분 때문에 문제가 발생할 경우가 있으므로 그 padding을 없애는 방법을 알아보자.
결론부터 말하자면
#pragma pack(n) //n = 1, 2, 4, 8, 16 ...
구조체 선언부 위에 이 문장을 삽입하면 된다. 이것의 의미는 구조체를 정렬할 때 n바이트 단위로 정렬을 하라는 이야기다. 지정해준 n과 구조체의 멤버 중 가장 큰 멤버의 크기와 비교해서 더 작은 것에 맞추어서 정렬을 한다.
기본적으로 정렬을 할 때 멤버의 가장 큰 데이터형을 찾아서 메모리에 정렬을 하도록 되어있지만 위의 문장은 멤버 데이터형의 크기보다 작은 n바이트 정렬을 가능하게 한다. 그렇게 해서 padding을 없애는 것이다.
위의 예제를 아래와 같이 수정해보자
#pragma pack(2) //2바이트로 메모리를 정렬
struct StructA{
char a;
int b;
char c;
int d;
}
이렇게 한다면 메모리에 할당되는 그림은 아래와 같을 것이다.
[char a 1byte, padding 1byte][int b 2byte][int b 2byte][char c 1byte, padding 1byte][int d 2byte][int d 2byte]
padding이 2바이트로 줄었다.
그리고 만약 #pragma pack(1) 로 설정한다면 padding은 완전히 사라지고 구조체의 크기는 10바이트로 정확히 맞추어질 것이다.
#pragma pack(1)을 사용한 후 메모리 모습
[char a 1byte][int b 1byte][int b 1byte][int b 1byte][int b 1byte]
[char c 1byte][int d 1byte][int d 1byte][int d 1byte][int d 1byte]
[출처] 구조체가 메모리에 할당되는 방법|작성자 곰더리