데이터 관리나 네트워크 통신에서 자주 사용되는 메모리 정렬
운영체제가 바뀌거나 네트워크 환경 변화에 의해서 오류가 나는 경우, 클라이언트에서 서버로 보낼 때 메모리 크기가 변경되는 경우가 있음
자료형의 바이트 크기를 구하는 연산자 SIZEOF
struct guessByte1
{
char guessChar;
};
std::cout << sizeof(guessByte1) << std::endl;
struct guessByte2
{
char guessChar;
int guessInt;
};
std::cout << sizeof(guessByte2) << std::endl;
구조체 guessByte1는 1byte
guessByte2는 5byte라고 예상해 볼 수 있다
하지만 결과는
guessByte1는 1byte
guessByte2는 8byte
컴파일러가 메모리 관리의 효율성을 위해서 구조체 멤버들의 크기를 조정하기 때문이다
윈도우 환경에서 메모리를 효율적으로 관리하기 위해서, 컴퓨터 메모리가 8G라고 가정했을 떄, 8 x 1024 x 1024 크기의 메모리 공간을 4개(4BYTE)묶어서 계산하는 바이트 정렬(alignment) 방식을 사용한다. 4바이트 단위로 주소를 관리하기 위해서 1바이트 뒤에 3바이트의 padding을 추가해 4바이트로 관리하게 된다
struct S1
{
char myChar;
};
struct S2
{
char myChar1;
char myChar2;
int myInt1;
int myInt2;
};
std::cout << sizeof(S2) << std::endl;
S2의 크기는 10으로 생각할 수 있지만 결과는 12가 나온다
클라이언트는 대부분 윈도우 환경이고 서버는 대부분 리눅스 환경으로
윈도우 환경에서는 4바이트 정렬을 사용하지만 리눅스는 1바이트 정렬을 사용한다 이 것은 모두 운영체제가 메모리를 관리하기 때문에 생기는 일
하지만 클라이언트와 서버가 네트워크로 통신하면 데이터를 정확하게 맞춰서 최소화 시켜야 통신 효율성이 증가함 그래서 바이트 숫자를 맞춰야할 상황이 생길 수 있음
해결책
#pragma 지시자 사용
컴파일러의 여러가지 도움이 되는 정보를 수정할 수 있는 지시자 중 구조체의 바이트를 관리하는 pack() 기능을 사용
packing은 push, pop용어를 이용해 바이트를 묶을 기준을 관리할 수 있다
#pragma pack(push,1)
struct guessByte2
{
char guessChar;
int guessInt;
};
#pragma pack(pop)
#pragma pack(push,1)
// 1바이트 단위로 메모리를 패킹한다는 정보를 보냄
// 이 라인 이후는 모두 1바이트 단위로 패킹됨을 뜻함
#pragma pack(pop)
// 패킹 정보를 꺼냄
// 1바이트 단위 패킹을 꺼내고 기본값으로 되돌아감