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]

+ Recent posts