LoginSignup
7

More than 5 years have passed since last update.

Pythonのctypesで、構造体のメンバへのポインタを取得する

Last updated at Posted at 2017-08-28

Pythonのctypesでこういうことをしたかった

typedef struct{
    int x;
    int y;
} point;
point p = {100, 200};
someFunc(&p.y); //yへのポインタを渡す

ただ普通に書いたところで

from ctypes import *

class Point(Structure):
    _fields_ = [("x", c_int), ("y", c_int)]

p = Point(100, 200)
somedll.someFunc(byref(p.y))

TypeError: byref() argument must be a ctypes instance, not 'int'

と怒られてしまう
p.yで得られる値はctypesインスタンスではなく、ただの(Pythonの)int数値なので、byrefしたところで参照をとることはできない

こうする

y_offset = Point.y.offset
y_addr = addressof(p) + y_offset
somedll.someFunc(y_addr)

取得したのはポインタというかアドレスそのものだがまあ同じようなもんだろう

どうも
(Structureのサブクラスの)クラスオブジェクト.メンバ名.offset
でそのメンバの、構造体先頭からのオフセットを取得することができるようだ
構造体先頭のアドレスを取得し、オフセットを足してやれば晴れてメンバのアドレスを取得できるというわけだ

ちなみに
クラスオブジェクト.メンバ名.size
でそのメンバのサイズを取得することができる

多用するなら以下のように関数化しておくとよいのではないか

def get_address_of_member(obj, member_name):
    return addressof(obj) + obj.__class__.__dict__[member_name].offset

p = Point(100, 200)
somedll.someFunc(get_address_of_member(p, "y"))

なんかスマートではない気がするがまあいいか
もっといい方法があれば、是非ご教示していただければ幸いです

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7