ctypes:使用lib.so(在Mac上)时指针地址修改但在使用lib.dll时没有(在Windows上)

时间:2016-02-16 19:39:29

标签: python c++ windows macos ctypes

来源

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

     来自PolyWrapper import *

     

P = Poly()

     

P.Print()

终端输出

  

self.obj的地址0x10038fc08

     

foo的地址:0x1804810

     

分段错误:11

控制台

  

流程:python2.7 [3359]

     

路径:/ Users / USER / * / python2.7

     

标识符:python2.7

     

代码类型:X86-64(原生)   家长程序:bash [3341]   负责人:终端[235]

     

日期/时间:2016-02-16 12:48:22.220 -0500   操作系统版本:Mac OS X 10.11.3(15D21)

     

异常类型:EXC_BAD_ACCESS(SIGSEGV)

     

异常代码:KERN_INVALID_ADDRESS位于0x0000000001804810

描述

问题

为什么这可以在我的Windows平台上运行,而不是在其他任何地方?

我在任一平台上都没有出现任何编译器错误。另外,我使用typedef来通过函数模板并没有给我带来其他类似项目的问题。

可能的线索

  • 请注意,.cpp文件中打印的foo&#39;地址与在控制台中引发警报的地址相同&#39;例外代码&#39;。 python在创建新对象时是否收到正确的地址?怎么说,怎么可能?

  • 报告了类似的问题here,但我不相信这是问题所在,因为我已明确设置restypeargtype和{ {1}}。

  • argtypes - g++ --version(OS X)和Apple LLVM version 7.0.2 (clang-700.1.81)(Windows CygWIN)。如果您认为编译器可能是问题,请注意我使用相同的编译器生成lib.so和lib.dll。 Spyder的执行(Python(x,y))有效;从CygWIN shell执行lib.so给出了SIG11。

1 个答案:

答案 0 :(得分:2)

这是我的最终解决方案。我没有对c ++方面做过任何重大改变 - 只有Python ctypes绑定。我还添加了一些逻辑来处理动态库(共享对象)的导入,这不是一般的。它适用于我的两个工作站和其他一些我必须协作的其他工作站,除了32位版本的Python2.7。

经验教训:

  • 使用不同的平台(Unix与Windows,32位与64位等)时,请注意数字的默认位长度。
  • 利用类属性:(i)良好的编码实践,以及(ii)确保__del__例程可以轻松链接到c ++对象的析构函数例程,这在传递时是必不可少的来回作为指针。
  • 我犯了将lib称为全局的错误,直到唤起__del__才给我带来问题;但是,在调用lib.Poly_del(self.obj)时,lib不再被定义。

Python绑定(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)