Python
C
ctypes

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

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"))

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