본문 바로가기
Python

[Python] `struct` 사용하기: bytes 로 C언어 구조체 다루기.

by ds31x 2024. 1. 15.

struct 모듈은 binary data를 보다 쉽게 파싱해주는 기능을 제공한다.

 

C언어의 구조체로 명시된 binary data를 네트워크 등으로 받은 경우나,
binary format으로 특정 header정보를 가지고 있는 파일들을 읽어들일 때,
특정 바이트 크기에 할당된 변수 값들을 Python의 변수들에 제대로 할당하는데 많이 사용된다.

 

크게 다음 3가지의 함수를 이용한다.


pack

C 언어의 구조체 등으로 읽어들일 수 있는 binary data에 해당하는 bytes객체를 만들어내는 함수.

현재 python의 변수들의 값들을 지정된 format의 binary data에 해당하는 bytes객체로 변경한다.

bytes_v = struct.pack(format, variable0, variable1, ...)
  • Python 변수들 (`variable0, variable1, ...)을
  • 특정 format에 따라 인코딩(?)하여
  • bytes객체를 생성함.

해당 bytes 객체를 파일로 저장하면 C언어로 같은 format을 따르는 구조체 변수로 읽어들일 수 있음.

위에서 format을 지정하는 format string은 다음의 표를 참고할 것.

Formatting String Python C Size 
(Bytes)
 
x - padding type 1 Null byte 로 패딩
C str (len이 1인) char 1 unsigned byte
b signed byte (bytes or int) signed char 1 signed byte
B unsigned byte (byte or int) unsigned char 1 unsigned byte
h int short 2 정수형
H int unsigned short 2 정수형
i int int 4 정수형
I (uppercase of i) int unsigned int 4 정수형
l (lowercase of L) int long 4 정수형
L int unsigned long 4 정수형
q int long long 8 정수형
Q int unsigned long long 8 정수형
f float float 4 single precision floating point number
d float double 8 double precision floating point number
s str (or bytes) char[] count null terminated string
p str (or bytes) char[] 1+count Pascal string

bytes로 pack 할 경우에는 endianess도 지정해줘야 함.

format string 의 가장 앞에 다음의 문자들로 지정한다.

Formatting Character
(Endianess Character)
Byte Order Size Alignment
@ Native Native (C의 sizeof에 의해 결정) Native
= Native Standard (앞서 테이블에 기재된 size) none
> big endian Standard none
< littel endian Standard none
! network (=big endian) Standard none

unpack

pack의 inverse에 해당한다.

보통 다른 software와 패킷 통신 등을 할 때 많이 이용됨.
binary data 에 해당하는 bytes객체 data_bytes을 parsing하여 값들을 가진 tuple을 생성한다고 생각하면 쉽다.

tuple_v = struct.unpack(format, data_bytes)

calcsize

앞서 애기한 format_string을 argument로 받아서 해당 format_string의 바이트 크기를 반환해줌.

int_v = struct.calcsize(format_string)

Example 1

임의의 png파일을 다운로드하고 이름을 test.png로 바꾼 후

test.png
0.22MB

 

다음 python code의 py파일과 같은 디렉토리 놓고 수행해 볼 것.

  • png가 올바른 파일인지 확인하고,
  • header로부터 width와 height를 얻어내는 프로그램임.
fstr = 'test.png'

valid_png_hdr = b'\x89PNG\r\n\x1a\n'

with open(fstr,'rb') as f:
    read_data = f.read(30)
    print(read_data[:8])

    #w,h = struct.unpack('>16x2L6x', read_data)

    if read_data[:8] == valid_png_hdr:
        w, h = struct.unpack(
            '>LL', # '2L',
            read_data[16:24]
        )
        print( f"{fstr} is a valid png file. \n {w=},{h=}")
    else:
        print(f'{fstr} is not a valid png file')

Example 2

다음은 little endian 을 사용하여 다음의 C 구조체에 해당하는 데이터를 받아서 처리하는 경우의 예임.
(socket으로부터 받은 data를 pack을 통해 가상으로 만들어서 처리함)

import struct

i = 2
a = 1.
b = 3.
c = 88.

data_bytes = struct.pack('<Hfff',i,a,b,c)
print(data_bytes)

parsed = struct.unpack('<Hfff',data_bytes)
print(parsed)

 

pack에 대응하는 구조체 (C 언어)는 다음과 같음.

typedef union
{
    uint8_t data[14]:
    struct __attribute__((packed))
    {
        uint16_t i;
        float a;
        float b;
        float c;
    };
} dspacket_s;

참고자료들

https://docs.python.org/ko/3/library/struct.html

 

struct — Interpret bytes as packed binary data

Source code: Lib/struct.py This module converts between Python values and C structs represented as Python bytes objects. Compact format strings describe the intended conversions to/from Python valu...

docs.python.org

https://dsaint31.me/mkdocs_site/CE/ch04/ce04_02_byte_ordering/

 

BME228

Byte Ordering : Little Endian and Big Endian Jonathan Swift의 걸리버 여행기의 소인국에서 삶은 달걀을 깰 때, 상대적으로 둥근 쪽(big end)과 날카로운 쪽(little end) 중 어느 쪽으로 깨는지에 따라 big endian과 littl

dsaint31.me

https://coding-yoon.tistory.com/120

 

[C] UNION 공용체와 Struct 구조체를 이용해 간단한 패킷 만들기

안녕하세요. 오늘은 UNION과 STRUCT에 대해 이야기 하겠습니다. coding-yoon.tistory.com/119 [C] 구조체 포인터 접근과 최적화 요즘 기본기가 중요함을 느끼고 C를 공부하고 있습니다. 1. 구조체 단순히접근

coding-yoon.tistory.com

https://coding-yoon.tistory.com/171

 

[파이썬 프로젝트] Python Struct (feat.c언어)

안녕하세요. 요즘 LoRa에서 End Device에서 바이트형식으로 오는 데이터를 파싱하기 위해 bytearray로 골머리를 썩고 있는데, 연구실 형님이 Python Struct을 추천해서 알게 되었습니다. Python이 굉장히 잘

coding-yoon.tistory.com

 

728x90