Python 의 ctypes 에는 C 언어와 유사한 구조체 기능을 제공한다.
(https://docs.python.org/2/library/ctypes.html#structured-data-types)
사용방법은 아래와 같다.
1 2 3 4 5 6 7 8 9 10 11 12 13 | import ctypesclass my_struct(ctypes.Structure): _fields_ = [ ('data_1', ctypes.c_int), ('data_2', ctypes.c_int8), ('data_3', ctypes.c_uint8), ]print(ctypes.sizeof(my_struct))8 |
구조체 크기가 alignment 되는 것도 C 언어와 같다.
C 에서는 #pragma pack(1) 또는 __attribute__((packed)) 통해 padding 을 막듯이 여기서도 비슷하게 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import ctypesclass my_struct(ctypes.Structure): _pack_ = 1 _fields_ = [ ('data_1', ctypes.c_int), ('data_2', ctypes.c_int8), ('data_3', ctypes.c_uint8), ]print(ctypes.sizeof(my_struct))6 |
bit field 설정도 가능하다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import ctypesclass my_struct(ctypes.Structure): _pack_ = 1 _fields_ = [ ('data_1', ctypes.c_int, 8), ('data_2', ctypes.c_int, 8), ('data_3', ctypes.c_int, 16), ]print(ctypes.sizeof(my_struct))4 |
이렇게 타입을 섞으면 안된다...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | import ctypesclass my_struct(ctypes.Structure): _pack_ = 1 _fields_ = [ ('data_1', ctypes.c_int, 8), ('data_2', ctypes.c_int8, 8), ('data_3', ctypes.c_int, 16), ]print(ctypes.sizeof(my_struct))9 |
섞어도 문제없는 구조체가 필요했기에 삽질을 하며 아래와 같이 완성, 추가로 파일 read, write 기능도 넣었다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | import ctypesimport numpy as npfrom io import BytesIOclass struct_type: def __init__(self, bytes, ctype, count): self.bytes = bytes self.ctype = ctype self.count = countdef create_struct(type_map): def return_fields(): fields = list() for name, types in type_map.items(): fields.append((name, ctypes.c_byte * types.bytes)) return fields class Structure(ctypes.Structure): _pack_ = 1 _fields_ = return_fields() def __setattr__(self, key, value): buffer_ctypes = np.ctypeslib.as_ctypes(np.zeros(type_map[key].bytes, dtype=ctypes.c_byte)) if type_map[key].count == 1: value_ctypes = np.ctypeslib.as_ctypes(np.dtype(type_map[key].ctype).type(value)) fit = min(type_map[key].bytes, ctypes.sizeof(value_ctypes)) ctypes.memmove(ctypes.addressof(buffer_ctypes), ctypes.addressof(value_ctypes), fit) super(Structure, self).__setattr__(key, buffer_ctypes) else: if type_map[key].ctype is ctypes.c_char: if value == 0: byte = str.encode('') else: byte = str.encode(str(value)) value_ctypes = (ctypes.c_byte * len(byte)).from_buffer_copy(byte) else: value_ctypes = np.ctypeslib.as_ctypes(np.asarray(value, dtype=type_map[key].ctype)) fit = min(type_map[key].bytes, ctypes.sizeof(value_ctypes)) ctypes.memmove(ctypes.addressof(buffer_ctypes), ctypes.addressof(value_ctypes), fit) super(Structure, self).__setattr__(key, buffer_ctypes) def __getattribute__(self, key): if key not in type_map: return super(Structure, self).__getattribute__(key) data = super(Structure, self).__getattribute__(key) fit = min(type_map[key].bytes, ctypes.sizeof(type_map[key].ctype) * type_map[key].count) if type_map[key].ctype is ctypes.c_char: return bytes(data)[0:fit].decode().strip('\x00') else: buffer_ctypes = np.ctypeslib.as_ctypes(np.zeros(type_map[key].count, dtype=type_map[key].ctype)) ctypes.memmove(ctypes.addressof(buffer_ctypes), ctypes.addressof(data), fit) value = np.ctypeslib.as_array(buffer_ctypes) if type_map[key].count == 1: return np.asscalar(value) else: return value def clear(self): for name, types in type_map.items(): setattr(self, name, 0) def write(self, filename): with open(filename, 'wb') as f: f.write(self) f.close() def read(self, filename): with open(filename, 'rb') as f: BytesIO(f.read()).readinto(self) f.close() return Structure()my_struct_type = { # name, byte size, type, type count 'data_1': struct_type(1, ctypes.c_int, 1), 'data_2': struct_type(1, ctypes.c_int8, 1), 'data_3': struct_type(2, ctypes.c_int, 1),}st = create_struct(my_struct_type)print(ctypes.sizeof(st))4 |
'개발 > Python' 카테고리의 다른 글
| python netCDF4 패키지 설치 (0) | 2018.10.04 |
|---|---|
| julian date 계산 (0) | 2018.10.04 |