Python内存地址:Linux上Python3.5-3.9的变体

Python内存地址:Linux上Python3.5-3.9的变体,python,python-3.x,ctypes,memory-address,Python,Python 3.x,Ctypes,Memory Address,我偶然发现了一个令人困惑的问题。在尝试使用ctypes.CDLLlibX11.so手动关闭XDisplay以热修复VTK时,我尝试使用Python提供的XDisplay地址。这在Python3.8上运行良好,但在Python3.7上导致了一个错误。下面的代码演示如何解决在VTK中创建的XDisplay的问题。具体而言: disp\u id=self.ren\u win.GetGenericDisplayId disp_id_int=intdisp_id[1:][0],16 printdisp\u

我偶然发现了一个令人困惑的问题。在尝试使用ctypes.CDLLlibX11.so手动关闭XDisplay以热修复VTK时,我尝试使用Python提供的XDisplay地址。这在Python3.8上运行良好,但在Python3.7上导致了一个错误。下面的代码演示如何解决在VTK中创建的XDisplay的问题。具体而言:

disp\u id=self.ren\u win.GetGenericDisplayId disp_id_int=intdisp_id[1:][0],16 printdisp\u id,disp\u id\u int x11=ctypes.CDLLlibX11.so x11.XCloseDisplaydisp\u id\u int 当运行时,返回:

user@host:~/tmp$ python3.7 tmp19.py
0000558f843c5930_p_void 94074887231792
Current thread 0x00007f8145824740 (most recent call first):
  File "/home/alex/python/pyvista/pyvista/plotting/plotting.py", line 2769 in close
  File "/home/alex/python/pyvista/pyvista/plotting/plotting.py", line 4207 in show

user@host:~/tmp$ python3.8 tmp19.py
0000000003568de0_p_void 56004064
如您所见,Python3.8中的地址可以用于libX11.so,但不能用于Python3.7来关闭XDisplay窗口

如注释中所述,Python返回的内存地址始终与当前Python进程相关。然而,如果是这种情况,为什么某些版本的Python似乎会为idTrue返回非常大的地址,idTrue是Python初始化时创建的一种结构。更令人困惑的是,返回这些大值的Python版本在与libX11.so库接口时也会产生分段值

以下是Python 3.5-Python 3.9的结果:

user@host:~$ python3.5 -c "print(id(True))"
93962585975264
user@host:~$ python3.6 -c "print(id(True))"
10302848
user@host:~$ python3.7 -c "print(id(True))"
94134164615424
user@host:~$ python3.8 -c "print(id(True))"
11498848
user@host:~$ python3.9 -c "print(id(True))"
11374464
两个问题:

这是预期的行为吗?如果是这样的话,我想对于我在本地安装的版本,有一个编译器标志被打开/关闭。 是否有一种方法可以调整内存地址,从而为所有版本的Python获得一致的结果? 你依靠的是一个身份证。。。函数返回PyObject的内存地址

在cpython中,Py_True和Py_False是:

/*使用这些宏*/ 定义Py_False PyObject*&Py_False struct 定义Py_True PyObject*&Py_TrueStruct 实际情况:

/*表示布尔值的对象为False和True*/ 结构_longobject _Py_false结构={ PyVarObject\u HEAD\u INIT和PyBool\u类型,0 { 0 } }; 结构_longobject _Py_TrueStruct={ PyVarObject\u HEAD\u INIT和PyBool\u类型,1 { 1 } }; C全局变量的内存地址由编译器、链接器和动态加载程序决定,并且根据常量值存在未定义的行为

您取决于一个。。。函数返回PyObject的内存地址

在cpython中,Py_True和Py_False是:

/*使用这些宏*/ 定义Py_False PyObject*&Py_False struct 定义Py_True PyObject*&Py_TrueStruct 实际情况:

/*表示布尔值的对象为False和True*/ 结构_longobject _Py_false结构={ PyVarObject\u HEAD\u INIT和PyBool\u类型,0 { 0 } }; 结构_longobject _Py_TrueStruct={ PyVarObject\u HEAD\u INIT和PyBool\u类型,1 { 1 } };
C全局变量的内存地址由编译器、链接器和动态加载程序确定,根据常量值,存在未定义的行为

结果是,在我的64位Linux环境中,指针大于4GB,这与使用ctypes包装库时的默认行为不兼容。重复@MarkTolonen的评论:

因为参数类型将在64位系统上错误地传递值。除非另有说明,否则ctypes假定整数参数为32位整数

诀窍是将argtype设置为c_void_p:

x11=ctypes.CDLLlibX11.so x11.XCloseDisplay.argtypes=ctypes.c\u void\u p x11.XCloseDisplaydisp\u id\u int
在Python3.8上,这对我有效的原因是指针的地址恰好小到可以作为int32传递,而在Python3.7上,正好整数对于int32太大。相反,将其作为ctypes.c\u void\u p传递解决了这个问题。

结果是,在我的64位Linux环境中,指针大于4GB,这与使用ctypes包装库时的默认行为不兼容。重复@MarkTolonen的评论:

因为参数类型将在64位系统上错误地传递值。除非另有说明,否则ctypes假定整数参数为32位整数

诀窍是将argtype设置为c_void_p:

x11=ctypes.CDLLlibX11.so x11.XCloseDisplay.argtypes=ctypes.c\u void\u p x11.XCloseDisplaydisp\u id\u int
在Python3.8上,这对我有效的原因是指针的地址恰好小到可以作为int32传递,而在Python3.7上,正好整数对于int32太大。相反,将其作为ctypes.c\u void\u p传递解决了这个问题。

id返回的整数恰好是CPython上的地址,但这是一个实现细节。你能显示出实际的错误代码吗?你能澄清你试图对id的结果做什么吗?命令的输出不仅因版本而异,还因程序运行而异。只需重新运行该命令即可获得不同的输出!当前pid的基址在任何现代操作系统上都不是一个有意义的概念。每个进程都在自己的地址空间中运行,地址从0.Ed开始

由于参数类型将在64位系统上错误地传递值,因此@jasonharperIf XCloseDisplay接受一个指针,传递一个整数,而不是声明x11.XCloseDisplay.argtypes=ctypes.c_void_p。除非另有说明,否则ctypes假定整数参数为32位整数。如果3.5和3.7返回大于4GB的地址,这就可以解释了。id返回的整数恰好是CPython上的地址,但这是一个实现细节。你能显示出实际的错误代码吗?你能澄清你试图对id的结果做什么吗?命令的输出不仅因版本而异,还因程序运行而异。只需重新运行该命令即可获得不同的输出!当前pid的基址在任何现代操作系统上都不是一个有意义的概念。每个进程都在自己的地址空间中运行,地址从零开始。编辑以说明@jasonharperIf XCloseDisplay的更正采用指针,传递整数,但不声明x11.XCloseDisplay.argtypes=ctypes.c_void_p,因为参数类型将在64位系统上错误传递值。除非另有说明,否则ctypes假定整数参数为32位整数。如果3.5和3.7返回大于4GB的地址,这就可以解释了。谢谢,这是一个很好的开始,可以解释id是如何工作的,以及地址之间变化的可能原因,但我仍然想知道如何获取给定指针相对于python进程基址的相对地址。@AlexKaszynski看到最后一句话,你要求的是未定义的,非常正确,我更正了这个问题以解决这个问题。我仍然很好奇为什么Python 3.6、3.8和3.9给出的地址可以被libX11使用,而不是3.5和3.7。很可能,如果您使用UB,任何事情都可能发生。这是一个很好的开始,解释了id是如何工作的,以及地址之间变化的可能原因,但我仍然想知道如何获取给定指针相对于python进程基址的相对地址。@AlexKaszynski看到最后一句话,你要求的是未定义的,非常正确,我更正了这个问题以解决这个问题。我仍然很好奇,为什么Python 3.6、3.8和3.9给出的地址可以被libX11使用,而不是3.5和3.7。很可能,如果您使用UB,那么任何事情都可能发生。km就是设置x11.XCloseDisplay.argtypes=c_void_p,它实际上声明了参数类型,而且,您不必在每次调用XCloseDisplay时包装参数。没有正确设置argtypes/restype是人们在使用ctypes时遇到问题的原因之一。再次感谢@MarkTolonen,我已经相应地更新了我的注释。BKM将设置x11.XCloseDisplay.argtypes=c_void_p,它实际上声明了参数类型,并且您不必每次调用XCloseDisplay时都包装参数。没有正确设置argtypes/restype是人们在使用ctypes时遇到问题的原因之一。再次感谢@MarkTolonen,我已经相应地更新了我的评论。