CPython中id(obj)和ctypes.addressof(obj)有什么区别 [英] What is the difference between id(obj) and ctypes.addressof(obj) in CPython
问题描述
说我使用 ctypes模块
i = c_int(4)
然后,我尝试使用以下方法找出i的内存地址:
and afterwards I try to find out the memory address of i using:
id(i)
或
ctypes.addressof(i)
,目前产生不同的值.为什么会这样?
which, at the moment, yield different values. Why is that?
推荐答案
您所建议的情况是CPython的实现细节.
What you are suggesting should be the case is an implementation detail of CPython.
id()
函数:
返回对象的身份".这是一个整数,在该对象的生存期内,保证该对象是唯一且恒定的.
Return the "identity" of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime.
CPython实现细节:这是对象在内存中的地址.
CPython implementation detail: This is the address of the object in memory.
尽管它们在CPython中可能是等效的,但不能保证在其他Python实现中也是如此.
While they might be equivalent in CPython, this is not guaranteed to be true in other implementations of Python.
为什么即使在CPython中它们也有不同的值?
请注意,c_int
:
-
是一个Python对象. CPython的
id()
将返回它的地址.
is a Python Object. CPython's
id()
will return the address of this.
包含 4字节与C兼容的int
值. ctypes.addressof()
将返回它的地址.
contains a 4-byte C-compatible int
value. ctypes.addressof()
will return the address of this.
Python对象中的元数据占用空间.因此,这个4字节的值可能不会在Python对象的最开始就存在.
The metadata in a Python object takes up space. Because of this, that 4-byte value probably won't live at the very beginning of the Python object.
看这个例子:
>>> import ctypes
>>> i = ctypes.c_int(4)
>>> hex(id(i))
'0x22940d0'
>>> hex(ctypes.addressof(i))
'0x22940f8'
我们看到addressof
结果仅比id()
结果高0x28字节.反复试验几次,我们可以看到情况总是如此.因此,我想说的是,整个c_int
中实际int
值之前的Python对象元数据有0x28字节.
We see that the addressof
result is only 0x28 bytes higher than the result of id()
. Playing around with this a few times, we can see that this is always the case. Therefore, I'd say that there are 0x28 bytes of Python object metadata preceding the actual int
value in the overall c_int
.
在我上面的示例中:
c_int
___________
| | 0x22940d0 This is what id() returns
| metadata |
| |
| |
| |
| |
|___________|
| value | 0x22940f8 This is what addressof() returns
|___________|
在ctypes的CPython实现中,基本 CDataObject
(2.7.6源)有一个b_ptr
成员,该成员指向用于对象的C数据的存储块:
In the CPython implementation of ctypes, the base CDataObject
(2.7.6 source) has a b_ptr
member that points to the memory block used for the object's C data:
union value {
char c[16];
short s;
int i;
long l;
float f;
double d;
#ifdef HAVE_LONG_LONG
PY_LONG_LONG ll;
#endif
long double D;
};
struct tagCDataObject {
PyObject_HEAD
char *b_ptr; /* pointer to memory block */
int b_needsfree; /* need _we_ free the memory? */
CDataObject *b_base; /* pointer to base object or NULL */
Py_ssize_t b_size; /* size of memory block in bytes */
Py_ssize_t b_length; /* number of references we need */
Py_ssize_t b_index; /* index of this object into base's
b_object list */
PyObject *b_objects; /* dictionary of references we need
to keep, or Py_None */
union value b_value;
};
addressof
将以下指针作为Python整数返回:
addressof
returns this pointer as a Python integer:
static PyObject *
addressof(PyObject *self, PyObject *obj)
{
if (CDataObject_Check(obj))
return PyLong_FromVoidPtr(((CDataObject *)obj)->b_ptr);
PyErr_SetString(PyExc_TypeError,
"invalid type");
return NULL;
}
小型C对象使用CDataObject
的默认16字节b_value
成员.如上面的示例所示,此默认缓冲区用于c_int(4)
实例.我们可以在32位进程中打开ctype以自省c_int(4)
:
Small C objects use the default 16-byte b_value
member of the CDataObject
. As the example above shows, this default buffer is used for the c_int(4)
instance. We can turn ctypes on itself to introspect c_int(4)
in a 32-bit process:
>>> i = c_int(4)
>>> ci = CDataObject.from_address(id(i))
>>> ci
ob_base:
ob_refcnt: 1
ob_type: py_object(<class 'ctypes.c_long'>)
b_ptr: 3071814328
b_needsfree: 1
b_base: LP_CDataObject(<NULL>)
b_size: 4
b_length: 0
b_index: 0
b_objects: py_object(<NULL>)
b_value:
c: b'\x04'
s: 4
i: 4
l: 4
f: 5.605193857299268e-45
d: 2e-323
ll: 4
D: 0.0
>>> addressof(i)
3071814328
>>> id(i) + CDataObject.b_value.offset
3071814328
该技巧利用了CPython中的id
返回对象的基地址的事实.
This trick leverages the fact that id
in CPython returns the base address of an object.
这篇关于CPython中id(obj)和ctypes.addressof(obj)有什么区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!