Pythonは非常に柔軟性の高い言語であり、C言語の構造体を扱うことも可能です。そのためのライブラリとしてctypes
があります。この記事では、Pythonとctypes
を用いてC言語の構造体を扱う方法について説明します。
ctypesとは
ctypes
はC言語のデータ構造をPythonで扱うことができるライブラリです。Pythonをインストールするときにこのライブラリは標準でインストールされます。Cの構造体をPythonでも扱いたいときなどに非常に便利です。
例
今回紹介する例としては、C側で構造体のデータをバイナリでログとして出力し、Python側でC側で吐き出されたバイナリのログデータを読み込んで表示します。PythonでCのログを解析することで2次利用(可視化や機械学習)が各段にしやすいのでマスターしたい技術です。
import ctypes
import os
class ST_DATA(ctypes.Structure):
_pack_ = 1 # pragma pack (push, 1) と同等. これ入れないとデータがパディングされてしまう。
_fields_ = (
('ID', ctypes.c_long),
('result', ctypes.c_short),
('data', ctypes.c_double*10),
)
dataList = []
def ReadData(logFilePath:str):
global dataList
if os.path.exists(logFilePath):
with open(logFilePath, 'rb') as f:
readBytes = bytearray(f.read())
print(f"readBytes len: {len(readBytes)}")
logCnt = len(readBytes) / ctypes.sizeof(ST_DATA) # 構造体データが何個存在するか算出
print(f"logCnt:{logCnt}")
# 読みだしたデータから各構造体のデータに分割
for no in range(logCnt):
bytesArr = readBytes[no*ctypes.sizeof(ST_DATA) : (no+1)*ctypes.sizeof(ST_DATA)]
datum = ST_DATA.from_buffer(bytesArr) # binaryデータを構造体データに変換
dataList.append(datum)
else:
print("log is not exist")
if __name__ == "__main__":
filename = "log.bin" # 構造体データがいくつも書かれたバイナリファイル
# ログデータを読み込む
ReadData(filename)
# データの取得方法 例
print(dataList[0].ID) # 1番最初のログのIDを表示
print(dataList[0].result) # 1番最初のログのresultを表示
print(dataList[0].data[0]) # 1番最初のログのdataの1要素目を表示
print(dataList[0].data[9]) # 1番最初のログのdataの10要素目を表示
このコードは、C言語で生成されたバイナリログをPythonで読み込み、その内容を表示するものです。C言語の構造体をPythonで扱うためには、ctypes
ライブラリを用いて構造体を定義します。この例では、ST_DATA
という名前の構造体を定義しています。
このように、Pythonとctypes
を用いることで、C言語の構造体を扱うことが可能となります。これにより、Pythonの柔軟性とC言語のパフォーマンスを組み合わせたプログラムを作成することができます。.