【问题标题】:How do you correctly pass a pointer between calls with Python C-API如何在使用 Python C-API 的调用之间正确传递指针
【发布时间】:2021-09-29 19:06:05
【问题描述】:

我正在编写一个 python + c 模块,我正在尝试将一个指针传递给我需要的某个结构。我正在使用 PyCapsule 封装指针,但在从中检索指针时遇到问题。 使用的 C 函数如下:

static PyObject *
spam_new (PyObject *self, PyObject *args)
{
    unsigned int number;
    struct spam *pointer;

    if (!PyArg_ParseTuple(args, "I", &number)) {
        return NULL;
    }
    
    state = (struct spam*) malloc(sizeof (struct spam));
    if (state == NULL) {
        return NULL;
    }
    spam_init(*pointer, number);
    return PyCapsule_New((void*) pointer, "spam", &spam_destroy);
}

static PyObject *
spam_get (PyObject *self, PyObject *args)
{
    PyObject *capsule, *result;
    void *raw_pointer;
    struct spam *pointer;
    unsigned long long int number;

    if (!PyArg_ParseTuple(args, "OK", capsule, &number)) {
        return NULL;
    }

    printf("[DEBUG] Number: %llu\n", number);
    printf("[DEBUG] Capsule pointer: %p\n", capsule);
    raw_pointer = PyCapsule_GetPointer(capsule, "spam");
    if (raw_pointer == NULL) {
        return NULL;
    }
    pointer = (struct spam*) raw_pointer;
    
    .
    .
    .
}

它们都用 METH_VARARGS 声明。 在 python 中,custom.new(1) 按预期返回一个胶囊,我将它存储在一个变量 c 中。 当调用 custom.get(c, 14) python 在 PyCapsule_GetPointer 函数调用时崩溃。两个打印显示相同 (14),这意味着 PyArg_ParseTuple 没有将胶囊作为参数传递。

出于安全原因,将指针作为 long 传递不是一种选择。

谢谢。

【问题讨论】:

  • PyArg_ParseTuple的调用不能修改capsule;在没有未初始化变量警告的情况下如何构建?
  • 我不知道,但它没有发出任何警告。它确实将胶囊修改为与另一个参数相同的值(指向内存地址 0x00...0014
  • 它不会修改capsule,因为你没有拿到它的地址。

标签: python c cpython


【解决方案1】:

Python documentation 中声明“O”格式字符串将尝试获取指向PyObject(PyObject*)的指针,而不是PyObject。

因此,当使用PyArg_ParseTuple 获取 PyObject* 时,您必须将指针传递给 PyObject*。

提供的代码已通过在该行的胶囊中添加 & 来修复

if (!PyArg_ParseTuple(args, "OK", &capsule, &number)) {

感谢Davis Herring的评论已修复。

【讨论】:

    猜你喜欢
    • 2012-01-16
    • 1970-01-01
    • 2017-03-03
    • 1970-01-01
    • 1970-01-01
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    • 2013-11-22
    相关资源
    最近更新 更多