파이썬 표준 라이브러리의 struct 모듈은 C 언어의 구조체(struct)와 파이썬의 bytes 객체 간 변환을 수행할 때 매우 유용하게 사용됩니다. 이러한 변환 작업은 모듈 레벨 함수를 통해서도 가능하고, struct 모듈에 정의된 Struct 클래스와 그 메서드를 통해서도 수행할 수 있습니다.
변환 함수들은 포맷 문자열(format string)을 사용하며, 이 문자열에서 바이트 순서(byte order), 크기(size), 정렬(alignment) 방식은 아래 표의 포매팅 문자에 따라 결정됩니다.
| 문자 | 바이트 순서 | 크기 | 정렬 |
|---|---|---|---|
| @ | 네이티브(native) | 네이티브(native) | 네이티브(native) |
| = | 네이티브(native) | 표준(standard) | 없음 |
| < | 리틀 엔디안(little-endian) | 표준(standard) | 없음 |
| > | 빅 엔디안(big-endian) | 표준(standard) | 없음 |
| ! | 네트워크(= 빅 엔디안) | 표준(standard) | 없음 |
C 타입과 파이썬 타입의 대응 관계
다음 표는 C 언어 타입 변수를 나타내는 포맷 문자와 그에 대응하는 파이썬 타입을 보여줍니다.
| 포맷 | C 타입 | 파이썬 타입 |
|---|---|---|
| x | 패딩 바이트(pad byte) | 값 없음 |
| c | char | 길이 1인 bytes |
| b / B | signed char / unsigned char | 정수(integer) |
| ? | _Bool | bool |
| h / H | short / unsigned short | 정수(integer) |
| i / I | int / unsigned int | 정수(integer) |
| l / L | long / unsigned long | 정수(integer) |
| f | float | 실수(float) |
| d | double | 실수(float) |
| s | char[] | bytes |
| p | char[] (Pascal 문자열) | bytes |
| P | void * | 정수(integer) |
struct 모듈의 주요 함수
struct 모듈에는 다음과 같은 핵심 함수들이 정의되어 있습니다.
pack()
이 함수는 지정한 포맷 문자열에 따라 값들을 패킹(packing)하여 bytes 객체로 반환합니다. 포맷 문자열의 형식 문자는 전달되는 값들과 반드시 일치해야 합니다.
unpack()
이 함수는 버퍼(buffer)에서 포맷 문자열에 따라 값을 언패킹(unpacking)합니다. 결과가 단 하나의 항목만 포함하더라도 항상 튜플(tuple) 형태로 반환됩니다.
다음 코드는 이 두 함수의 사용 예를 보여줍니다.
import struct
student=(1, b'Rahul', 65.75)
packed=struct.pack('I 5s f', *student)
print ('packed data:',packed)
unpacked=struct.unpack('I 5s f', packed)
print ('unpacked data:',unpacked)실행 결과
packed data: b'\x01\x00\x00\x00Rahul\x00\x00\x00\x00\x80\x83B' unpacked data: (1, b'Rahul', 65.75)
Struct 클래스 활용하기
패킹/언패킹 작업은 Struct 클래스의 메서드를 통해서도 수행할 수 있습니다. Struct 객체를 한 번 생성한 후 그 메서드를 호출하는 방식은, 동일한 포맷 문자열로 struct 모듈의 함수를 반복 호출하는 것보다 더 효율적입니다. 그 이유는 포맷 문자열이 한 번만 컴파일되기 때문입니다.
Struct(format)
이 생성자는 지정한 포맷 문자열 형식에 따라 바이너리 데이터를 읽고 쓰는 새로운 Struct 객체를 반환합니다.
pack()
컴파일된 포맷을 사용한다는 점을 제외하면 pack() 함수와 동일하게 동작하는 메서드입니다.
unpack()
컴파일된 포맷을 사용한다는 점을 제외하면 unpack() 함수와 동일하게 동작하는 메서드입니다.
다음 예제는 Struct 클래스를 사용해 파이썬 데이터를 패킹하고 언패킹하는 방법을 보여줍니다.
s = struct.Struct('I 5s f')
packed=s.pack(*student)
print (packed)
unpacked = s.unpack(packed)
print (unpacked)namedtuple로 결과 변환하기
패킹된 데이터는 namedtuple 객체로 직접 변환하여 파싱할 수도 있습니다. 이렇게 하면 인덱스 대신 의미 있는 필드 이름으로 데이터에 접근할 수 있어 가독성이 크게 향상됩니다.
from collections import namedtuple
newstudent = namedtuple('newstudent','No Name Marks')
s1 = newstudent._make(struct.unpack('I 5s f', packed))
print (s1)실행 결과
newstudent(No=1, Name=b'Rahul', Marks=65.75)