为什么 ctypes.addressof() 与 ctypes.Structure 对象的 id() 不匹配?
Why does ctypes.addressof() not match id() for ctypes.Structure objects?
这是我已经困扰了一段时间的问题,所以任何意见都将不胜感激。
运行 python 2.7 (cpython),考虑下面的ctypes.Structure表示一个SCSI通用IO结构:
import ctypes
class SGIOHeader(ctypes.Structure):
_fields_ = [
('interface_id', ctypes.c_int),
('dxfer_direction', ctypes.c_int),
('cmd_len', ctypes.c_ubyte),
('mx_sb_len', ctypes.c_ubyte),
('iovec_count', ctypes.c_ushort),
('dxfer_len', ctypes.c_uint),
('dxferp', ctypes.c_void_p),
('cmdp', ctypes.c_void_p),
('sbp', ctypes.c_void_p),
('timeout', ctypes.c_uint),
('flags', ctypes.c_uint),
('pack_id', ctypes.c_int),
('usr_ptr', ctypes.c_void_p),
('status', ctypes.c_ubyte),
('masked_status', ctypes.c_ubyte),
('msg_status', ctypes.c_ubyte),
('sb_len_wr', ctypes.c_ubyte),
('host_status', ctypes.c_ushort),
('driver_status', ctypes.c_ushort),
('resid', ctypes.c_int),
('duration', ctypes.c_uint),
('info', ctypes.c_uint)]
如果我使用上述 class 实例化一个对象,我倾向于观察到 ctypes.addressof() 返回的内容与通过调用对象上的 id() 返回的内容相去甚远:
>>> sgio = SGIOHeader()
>>> hex(id(sgio))
'0x10eb5ed40'
>>> hex(ctypes.addressof(sgio))
'0x7fdeca700130'
我理解在 id() 和 ctypes.addressof() 之间应该有一个增量,对应于引用计数和对象识别所需的元数据。我不明白的是为什么对象的 python 地址与支持结构的内存地址相距如此之远?
这是一个问题的原因是,如果我尝试使用 ctypes.addressof() 值发出 ioctl,我将始终得到 EFAULT,因为该对象被认为在我的进程地址之外space。如果对象存在于堆中,它的后备地址怎么会与其身份相距如此之远呢?关于 python 对象在内存中的布局方式,我有什么误解?是否有不同的寻址方案(似乎我得到的是 32 位或 64 位值)?
因为建模的 C 结构和代理它的 Python 对象是两个不同的概念。
id()
为您提供 Python 代理对象的内存地址,ctypes.addressof()
为您提供实际 C 结构的地址。您不能将 Python 对象传递给其他 C 代码,但您 可以 将 C 结构传递给其他 C 代码。
这是我已经困扰了一段时间的问题,所以任何意见都将不胜感激。
运行 python 2.7 (cpython),考虑下面的ctypes.Structure表示一个SCSI通用IO结构:
import ctypes
class SGIOHeader(ctypes.Structure):
_fields_ = [
('interface_id', ctypes.c_int),
('dxfer_direction', ctypes.c_int),
('cmd_len', ctypes.c_ubyte),
('mx_sb_len', ctypes.c_ubyte),
('iovec_count', ctypes.c_ushort),
('dxfer_len', ctypes.c_uint),
('dxferp', ctypes.c_void_p),
('cmdp', ctypes.c_void_p),
('sbp', ctypes.c_void_p),
('timeout', ctypes.c_uint),
('flags', ctypes.c_uint),
('pack_id', ctypes.c_int),
('usr_ptr', ctypes.c_void_p),
('status', ctypes.c_ubyte),
('masked_status', ctypes.c_ubyte),
('msg_status', ctypes.c_ubyte),
('sb_len_wr', ctypes.c_ubyte),
('host_status', ctypes.c_ushort),
('driver_status', ctypes.c_ushort),
('resid', ctypes.c_int),
('duration', ctypes.c_uint),
('info', ctypes.c_uint)]
如果我使用上述 class 实例化一个对象,我倾向于观察到 ctypes.addressof() 返回的内容与通过调用对象上的 id() 返回的内容相去甚远:
>>> sgio = SGIOHeader()
>>> hex(id(sgio))
'0x10eb5ed40'
>>> hex(ctypes.addressof(sgio))
'0x7fdeca700130'
我理解在 id() 和 ctypes.addressof() 之间应该有一个增量,对应于引用计数和对象识别所需的元数据。我不明白的是为什么对象的 python 地址与支持结构的内存地址相距如此之远?
这是一个问题的原因是,如果我尝试使用 ctypes.addressof() 值发出 ioctl,我将始终得到 EFAULT,因为该对象被认为在我的进程地址之外space。如果对象存在于堆中,它的后备地址怎么会与其身份相距如此之远呢?关于 python 对象在内存中的布局方式,我有什么误解?是否有不同的寻址方案(似乎我得到的是 32 位或 64 位值)?
因为建模的 C 结构和代理它的 Python 对象是两个不同的概念。
id()
为您提供 Python 代理对象的内存地址,ctypes.addressof()
为您提供实际 C 结构的地址。您不能将 Python 对象传递给其他 C 代码,但您 可以 将 C 结构传递给其他 C 代码。