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 ctypes class 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 ctypes class 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 ctypes class 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 ctypes class 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 ctypes import numpy as np from io import BytesIO class struct_type: def __init__( self , bytes, ctype, count): self .bytes = bytes self .ctype = ctype self .count = count def 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 |