python - ctypes:使用 lib.so(在 Mac 上)时指针地址修改,但在使用 lib.dll(在 Windows 上)时不修改

标签 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

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 ,但我不认为这是这里的问题,因为我已经明确设置了 restypeargtypeargtypes

  • 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/

相关文章:

python - 在嵌套字典中查找最大值

python - 如何在 pudb 中查看变量?

python - 使用 Python 将图像嵌入到 SVG 文件中,例如 Inkscape 扩展

c++ - 使用 SSE 计算矩阵乘积比使用直接算法慢得多

c++ - C++ 的任何命令行解析库是否允许带有 N 个参数的选项

python - 使用 Django 在用户注册时填写用户个人资料

.net - 通过应用程序解锁Win7桌面

windows - Windows 上 PHP 的当前路径(独立 CLI)

c# - 在 Windows 上更改任务栏按钮颜色

C++ 筛选堆