[Python] CとのFFI用の構造体の配列
2 min
356 words
Suzuki Shun
PythonからCの関数を呼び出すとき, Cの関数の引数に構造体の配列を渡すことがある.
構造体はctypes.Structure
を継承したクラスを作ればいいというのはよく知られているが, その配列をどうやって作るかがあんまり調べても出てこなかったのでメモ.
結論から言うと, 普通にnumpy
の配列を使えば良い.
ただし, フィールドへのアクセスを文字列で行う必要がある.
import ctypes
import numpy as np
class Point(ctypes.Structure):
_fields_ = [("x", ctypes.c_double), ("y", ctypes.c_double)]
size = 2
points = np.zeros(size, dtype=Point)
for i in range(size):
points[i]["x"] = 2 * i
points[i]["y"] = 2 * i + 1
print(points)
# [(0., 1.) (2., 3.)]
これで作った配列は以下のようにポインタに変換できる.
これは, Cで言うところのPoint* ptr
に相当する.
ptr = points.ctypes.data_as(ctypes.POINTER(Point))
補足
上記のpoints
の各要素の型はnumpy.void
となっている.
そのため, Point
の要素から直接は構成できない.
例えば, 以下のコードはValueError: could not convert string to float
というエラーを吐く.
(このエラーだいぶ分かりづらいな...)
points = np.fromiter(map(lambda i: Point(2 * i, 2 * i + 1), range(size)), dtype=Point)
こういう場合は, numpy.void
に明示的に変換する必要がある.
points = np.fromiter(
map(lambda i: np.void(Point(2 * i, 2 * i + 1)), range(size)), dtype=Point
)
Table of contents