C언어/잡학사전

[C/C++] 구조체 패킹 (struct packing)

아무일도없었다 2022. 10. 11. 11:48

패킹을 이해하기 전 패딩의 개념을 알아야 한다.

 

https://hackerpark.tistory.com/entry/CC-%EA%B5%AC%EC%A1%B0%EC%B2%B4%ED%81%B4%EB%9E%98%EC%8A%A4-%ED%8C%A8%EB%94%A9-struct-class-padding

 

[C/C++] 구조체(클래스) 패딩 (struct, class padding)

패딩 (padding) 패딩이란 CPU의 효율을 높이기 위해서 효율적으로 메모리를 사용하는 기법 중에 하나이다. (여기서의 효율이란 저장 공간 효율이 아닌 데이터 처리 속도 효율을 의미한다.) 어떤 식

hackerpark.tistory.com

 

 

패킹


패킹 (packing) 이란 패딩 규칙에서 기준이 되는 memory block 크기를 변경해서 memory 에 데이터의 위치를 조절하는 것이다.

 

기준이 되는 패킹 크기는 컴파일러마다 다르니 개발 시 사용하는 컴파일러의 패킹 크기 확인을 해두면 좋다. 예를 들어 msdn 의 경우 default 패킹 크기가 8byte 이다. 자세한 내용은 아래 참고)

https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-6.0/aa273913(v=vs.60)?redirectedfrom=MSDN 

 

pack

Table of contents pack Article 09/15/2006 2 minutes to read In this article --> #pragma pack( [ n] ) Specifies packing alignment for structure and union members. Whereas the packing alignment of structures and unions is set for an entire translation unit b

learn.microsoft.com

 

 

 

패딩을 사용하는 이유는 CPU 의 처리 효율 증가였다면, 패킹은 주로 네트워크에서 주고받는 패킷의 직렬화(serialize)를 위해 사용한다.

 

직렬화란 쉽게 말해 구조체 사이에 들어가 있는 패딩 바이트를 모조리 빼버리고 데이터를 압축하는 것이다.

 

패킹의 크기를 1byte 로 설정한다면 빈 공간 없이 (패딩 바이트) memory 에 저장된다.

 

직렬화 (1byte 패킹)

 

네트워크에서 패킷의 직렬화를 사용하는 주된 이유는 통신하는 모듈의 개발 언어 및 환경이 모두 같을 수 없기 때문이다.

 

C 모듈과 Java 모듈 간의 네트워크 통신을 하는 환경에서 직렬화를 했을 때와 하지 않았을 때를 가정해보자.

 

C 에서는 struct (구조체) 를 지원하고 이는 자동으로 패딩이 되어있는 상태로 프로세스의 메모리에 저장되어있을 것이다.

 

Java 의 경우는 struct 를 지원하지 않고 패킷 데이터로부터 데이터를 크기 별로 파싱해서 각 변수마다 value 를 저장해야 한다.

 

따라서 C 모듈에서 struct 에 데이터를 담아서 Java 모듈에 데이터를 전달했는데 직렬화가 되어있지 않다면 Java 에서는 중간에 들어가 있는 패딩 바이트를 모르기 때문에 엉뚱한 값을 읽을 가능성이 높다.

 

또한 직렬화를 하지 않은 경우 패딩 바이트로 인해 데이터의 크기가 상대적으로 크기 때문에 이는 네트워크에서도 성능 문제와 연결될 수 있다.

 


 

패킹 방법


 

위에서 잠깐 언급했듯이 패킹은 사용하는 컴파일러마다 다르기 때문에 사용 중인 컴파일러의 패킹 방법을 숙지하고 있어야 한다.

 

(Windows) MS Compiler 의 경우 (MS Visual Studio)

#pragma pack(push, 1) // 이후 구조체 선언 시 1byte 패킹

// 여기에 구조체 정의

#pragma pack(pop) // 패킹 종료

 

#pragma pack(push, n) 지시어를 사용해서 n byte 의 패킹을 사용자가 지정할 수 있다.

(대부분 1byte 패킹을 통해 직렬화에 사용한다.)

 

주의할 내용은 패킹할 구조체 선언이 모두 완료된 이후 #pragma pack(pop) 을 통해 패킹을 종료해야 한다. (돌려놓지 않는 경우 모든 구조체에 패킹이 적용되며, 이는 심각한 오류로 이어질 수 있다.)

 


 

(Unix & Linux) GCC 컴파일러의 경우

typedef struct {
    char a[10];
    int b;
    long c;
    short d;
    int e;
} __attribute__((packed)) my_struct_t;  // __attribute__((packed)) 지시자를 통한 패킹

 

GCC 는 __attribute__((packed)) 를 사용하여 패킹을 할 수 있으며 1byte 크기로 패킹해준다.

 

MS 처럼 특별히 종료하지 않고 패킹이 필요한 구조체 선언 시 지시어를 사용하면 된다.

 


 

(IBM) XLC & XLC++ 컴파일러의 경우

#pragma options align=packed // 이후 구조체 선언시 1byte 패킹

// 여기에 구조체 정의

#pragma options align=reset // 패킹 종료

 

#pragma options align=packed 지시어 사용 이후 선언된 모든 구조체는 1byte 패킹이 된다.

 

Windows 와 동일하게 패킹할 구조체 선언이 모두 완료된 이후 #pragma options align=reset 을 통해 패킹을 종료해야 한다.

 

 

반응형