来源
C++
/*** type define class template for extern "C" ***/
typedef Mpoly<double> MpolyDouble;
// Declare functions as extern "C" for ctypes
//
// >> compiler statement (mac/linux): g++ -shared -o libPoly.so -fPIC libPoly.cpp
// >> compiler statement (windows): g++ -shared -o libPoly.dll libPoly.cpp
//
extern "C" {
/*** libPoly Constructor/Destructor Routines ***/
MpolyDouble* Poly_new(int size, int dim) { return new(nothrow) MpolyDouble(size,dim); }
void Poly_del(MpolyDouble* foo) { delete foo; }
/*** libPoly Miscellaneous Routines ***/
void PolyPrint(MpolyDouble* foo) {
// print out address of object pointer
std::cout << "address of foo: " << foo << std::endl;
// call MpolyDouble.print() method
foo->print();
}
}
python
#*** import python libraries ***#
from ctypes import *
from numpy.ctypeslib import ndpointer
import numpy as np
import weakref
#**************************************#
#*** load the libPoly shared object ***#
#**************************************#
lib = CDLL('./libPoly.so') #! for Mac/Linux
#lib = CDLL('./libPoly.dll') #! for Windows
#********************************************************#
#*** set the argument types for each member attribute ***#
#********************************************************#
## Poly_new
lib.Poly_new.argtypes = [c_int, c_int]
lib.Poly_new.restype = c_void_p
## Poly_del
lib.Poly_del.argtypes = [c_void_p] #<---edit
lib.Poly_del.restype = None
## PolyPrint
lib.PolyPrint.argtypes = [c_void_p] #<---edit
lib.PolyPrint.restype = None
#********************************************************#
#*** define a python class Poly ***#
#********************************************************#
class Poly(object):
# GHV Instantiation Routine:
def __init__(self,size=1,dim=2):
# ensure that the input args are of correct type
size = int(size)
dim = int(dim)
# call the C/C++ function
self.obj = lib.Poly_new(size,dim)
def __del__(self):
lib.Poly_del(self.obj)
self._obj = None
# GHV Print Routine:
def Print(self):
print 'address of self.obj',hex(id(self.obj))
# call the C/C++ function
lib.PolyPrint(self.obj)
OS X(示例)实现
终端
$ python
from PolyWrapper import *
P = Poly()
P.Print()
终端输出
address of self.obj 0x10038fc08
address of foo: 0x1804810
Segmentation fault: 11
控制台
Process: python2.7 [3359]
Path: /Users/USER/*/python2.7
Identifier: python2.7
Code Type: X86-64 (Native) Parent Process: bash [3341] Responsible: Terminal [235]
Date/Time: 2016-02-16 12:48:22.220 -0500 OS Version: Mac OS X 10.11.3 (15D21)
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Codes: KERN_INVALID_ADDRESS at 0x0000000001804810
描述
问题
为什么这在我的 Windows 平台上有效,但在其他任何地方都无效?
我在这两个平台上都没有遇到任何编译器错误。此外,我使用 typedef 来通过函数模板并没有给我在其他类似项目中带来问题。
可能的线索
请注意,从 .cpp 文件中打印的“foo 的地址”与在控制台“异常代码”中引发警报的地址相同。 python 在创建新对象时是否收到正确的地址?如何判断,这怎么可能?
报告了类似的问题 here ,但我不认为这是这里的问题,因为我已经明确设置了
restype
、argtype
和argtypes
。g++ --version
--Apple LLVM 版本 7.0.2 (clang-700.1.81)
(OS X) 和g++ (GCC ) 2.9.3
(Windows CygWIN)。如果您认为编译器可能是问题所在,请注意我使用了同一个编译器来生成 lib.so 和 lib.dll。从 Spyder (Python (x,y)) 执行有效;从 CygWIN shell 执行 lib.so 给出 SIG11。
最佳答案
这是我的最终解决方案。我在 C++ 方面没有做任何重大更改——只有 Python ctypes 绑定(bind)。我还添加了一些逻辑来处理动态库(共享对象)的导入,这不是通用的。它适用于我的两个工作站和我必须协作的其他几个工作站,但 Python2.7 的 32 位版本除外。
经验教训:
- 在使用不同平台(Unix 与 Windows、32 位与 64 位等)时,请注意数字的默认位长度。
- 利用类属性来:(i) 良好的编码实践,以及 (ii) 确保
__del__
例程可以轻松链接到 c++ 对象的析构函数例程,这在传递对象时必不可少来回作为指针。 - 我错误地将
lib
作为全局调用,直到调用__del__
才给我带来问题;然而,当lib.Poly_del(self.obj)
被调用时,lib
不再被定义。
Python 绑定(bind) (PolyWrapper.py)
#*************************************#
#*** import python libraries ***#
#*************************************#
from ctypes import *
from numpy.ctypeslib import ndpointer
import numpy as np
import weakref
import platform
#**************************************#
#*** load the libPoly shared object ***#
#**************************************#
print.system()
if (platform.system() == "Windows" or platform.system() == "CYGWIN-6.1"):
lib = CDLL('./libPoly.dll')
else:
lib = CDLL('./libPoly.so')
#********************************************************#
#*** set the argument types for each member attribute ***#
#********************************************************#
## Poly_new
lib.Poly_new.argtypes = [c_int, c_int]
lib.Poly_new.restype = c_void_p
## Poly_del
lib.Poly_del.argtypes = [c_void_p]
lib.Poly_del.restype = None
## PolyPrint
lib.PolyPrint.argtypes = [c_void_p]
lib.PolyPrint.restype = None
#********************************************************#
#*** define a python class Poly ***#
#********************************************************#
class Poly(object):
_obj = None
_local = lib
# Poly Instantiation Routine:
def __init__(self,size=1,dim=1):
# ensure that the input args are of correct type
size = int(size)
dim = int(dim)
# call the C/C++ function
self._obj = c_void_p(self._lib.Poly_new(size,dim))
# Poly Destructor Routine:
def __del__(self):
if (self._obj is not None):
self._lib.Poly_del(self._obj)
del self._obj
# Poly Print Routine:
def Print(self):
# call the C/C++ function
self._lib.PolyPrint(self._obj)
关于python - ctypes:使用 lib.so(在 Mac 上)时指针地址修改,但在使用 lib.dll(在 Windows 上)时不修改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35441612/