python - 如何包装带有 void* 指针的 C 函数?

标签 python c dll cython

我正在尝试使用 Cython 包装 DLL 中定义的一些函数,困难在于许多函数使用指向 void* 的指针,这里是函数原型(prototype)的示例:

---------------"header.h"-----------------------

typedef void* HANDLE

int open(HANDLE* a_handle_pointer , int open_mode)

int use(HANDLE a_handle, int usage_mode )

C 中的用法示例是:

---------------"main.c" -----------------

#include"header.h"

HANDLE my_handle ;
int results ;
if(open(&my_handle ,1) == 0) /* open a handle with mode 1 */
{
    printf ("failed to open \n);
    return 0;
}

else printf("open success \n");

use(handle , 2); /* use handle (opened with open) in mode 2 */

正如您所说,除非已经使用“open”函数打开了句柄,否则“Use”函数无法执行某些操作,这使得它在 Python/cython 中变得困惑

这是我如何在 Cython 中定义“open”函数(几个试验之一)

from libc.stdint cimport uintptr_t
cdef extern from "header.h":
     ctypedef void*     HANDLE 
     int open(HANDLE* a_handle_pointer , int open_mode)


def Open( uintptr_t a_handle_pointer , int open_mode)

    return open(<HANDLE*> a_handle_pointer , open_mode)

我尝试按照一些人的建议将 void * 指针转换为 uintptr_t,但仍然收到错误:

" TypeError: an integer is required " when calling the function.

>>>from my_module import open
>>>open (handle , 1)

我该如何解决这个问题?

我想知道如何使用 void*void** 类型的参数从 Python 调用函数?

最佳答案

用 Python 本身编写模块/绑定(bind)是一个主意,特别是在涉及指针的情况下。你应该用 C 语言来做这样的事情...警告:这是特定于 CPython 3+ 的。 CPython 2 扩展的编码方式不同! 顺便说一句:将您的 open 函数重命名为 load,因为它与 POSIX 的 open(3) 冲突。 .

// my_module.c: My Python extension!

/* Get us the CPython headers.
 */
#include "Python.h"

/* And your function's headers, of course.
 */
#include "header.h"

/* Actual structures used to store
 * a 'my_module.Handle' internally.
 */
typedef struct
{
    PyObject_HEAD /* The base of all PyObjects. */
    HANDLE handle; /* Our handle, great! */
} my_module_HandleObject;

/* The type 'my_module.Handle'. This variable contains
 * a lot of strange, zero, and NULLified fields. Their
 * purpose and story is too obscure for SO, so better
 * off look at the docs for more details.
 */
static PyTypeObject my_module_HandleType =
{
    PyVarObject_HEAD_INIT(NULL, 0)
    "my_module.Handle", /* Of course, this is the type's name. */
    sizeof(my_module_HandleObject), /* An object's size. */
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ... Don't ask. */
    Py_TPFLAGS_DEFAULT, /* The type's flags. There's nothing special about ours, so use the defaults. */
    NULL /* No docstrings for you! */
};

/* The "wrapper" function. It takes a tuple of
 * CPython PyObject's and returns a PyObject.
 */
static PyObject *my_module_load(PyObject *self, PyObject *args)
{
    int load_mode;
    if(!PyArg_ParseTuple(args, "i", &load_mode) != 0) { /* Parse the argument list. It should have one single integer ("i") parameter. */
        return NULL;
    }

    /* Create a Handle object, so as to put
     * in itthe handle we're about to get.
     */
    my_module_HandleObject *the_object = PyObject_New(my_module_HandleObject, &my_module_HandleType);
    if(the_object == NULL) {
        return NULL;
    }

    /* Finally, do our stuff.
     */
    if(load(&the_object->handle, load_mode) == -1) {
        Py_DECREF(the_object);
        PyErr_SetFromErrno(NULL);
        return NULL;
    }

    return (PyObject*)the_object;
}

/* The method table. It is a list of structures, each
 * describing a method of our module.
 */
static struct PyMethodDef my_module_functions[] =
{
    {
        "load", /* The method's name, as seen from Python code. */
        (PyCFunction)my_module_load, /* The method itself. */
        METH_VARARGS, /* This means the method takes arguments. */
        NULL, /* We don't have documentation for this, do we? */
    }, { NULL, NULL, 0, NULL } /* End of the list. */
};

/* Used to describe the module itself. */
static struct PyModuleDef my_module =
{
    PyModuleDef_HEAD_INIT,
    "my_module", /* The module's name. */
    NULL, /* No docstring. */
    -1,
    my_module_functions,
    NULL, NULL, NULL, NULL
};

/* This function _must_ be named this way
 * in order for the module to be named as
 * 'my_module'. This function is sort of
 * the initialization routine for the module.
 */
PyMODINIT_FUNC PyInit_my_module()
{
    my_module_HandleType.tp_new = PyType_GenericNew; /* AFAIK, this is the type's constructor. Use the default. */
    if(PyType_Ready(&my_module_HandleType) < 0) { // Uh, oh. Something went wrong!
        return NULL;
    }

    PyObject *this_module = PyModule_Create(&my_module); /* Export the whole module. */
    if(this_module == NULL) {
        return NULL;
    }

    Py_INCREF(&my_module_HandleType);
    PyModule_AddObject(this_module, "Handle", (PyObject*)&my_module_HandleType);

    return this_module;
}

为了构建和安装扩展,see the docs on distutils .

关于python - 如何包装带有 void* 指针的 C 函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36049540/

相关文章:

c++ - 当调用dll函数时,参数对象的成员变量的内存地址发生变化

python - 除了 subprocess.Open 之外,有什么方法可以从 python 调用 "hadoop cp/distcp"吗?

python - 如何创建来自机器人的嵌入消息?

c - 处理字符串的链表,C

c# - 从 C# 调试 C++ dll

c++ - Visual Studio C++ 项目中所需的 DLL

python - 如何知道 urllib.urlretrieve 是否成功?

python - 类型错误 : unsupported operand type(s) for -: 'float' and 'NoneType' python

c - C 超出时间限制

c - 如何在 C 中的引号中使用变量