如何从C语言向Python传递字符串指针?

j0pj023g  于 2022-09-29  发布在  Python
关注(0)|答案(1)|浏览(178)

我需要将一个字符串指针从C传递到Python,这样Python就可以更新指针,C也可以稍后读取它。

步骤

  1. C设置一个char**
  2. C调用Python
  3. Python分配内存
  4. Python更新char**
  5. C读取字符串

C代码:

#include <stdio.h>

#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

typedef void (*CALLBACK)(char**);

CALLBACK g_cb;

// Expose API to register the callback
API void set_callback(CALLBACK cb) {
    g_cb = cb;
}

// Expose API to call the Python callback with a char**
API void call_python_function(char** pp) {
    if(g_cb) {
        g_cb(pp);
        printf("Python response: %s\n", *pp);
    }
}

Python代码:

import ctypes as ct

CALLBACK = ct.CFUNCTYPE(None, PPCHAR)

dll = ct.CDLL('./test')
dll.set_callback.argtypes = CALLBACK,
dll.set_callback.restype = None
dll.call_python_function.argtypes = POINTER(POINTER(ctypes.c_char)),
dll.call_python_function.restype = None
dll.set_callback(my_function)

def my_function(pp):
    buffer = ct.create_string_buffer(128)
    pp = buffer

输出:

Python response: (null)

编译时没有错误或警告,C可以调用Python函数,没有问题,但Python不能更新char**。我的问题是如何将字符串指针从C传递到Python?

djp7away

djp7away1#

下面是一个将char**从C传递到Python的工作示例。

测试.c

#include <stdio.h>

#ifdef _WIN32
#   define API __declspec(dllexport)
#else
#   define API
#endif

typedef void (*CALLBACK)(char**);

CALLBACK g_cb;

// Expose API to register the callback
API void set_callback(CALLBACK cb) {
    g_cb = cb;
}

// Expose API to call the Python callback with a char**
API void call_python_function(char** pp) {
    if(g_cb) {
        g_cb(pp);
        printf("%s\n", *pp);
    }
}

测试.py

import ctypes as ct

# Set up some types.
# Note that `c_char_p` can't be used as ctypes has special handling
# to convert it to a Python bytes object that inteferes with the
# callback working properly.
PCHAR = ct.POINTER(ct.c_char)
PPCHAR = ct.POINTER(PCHAR)
CALLBACK = ct.CFUNCTYPE(None, PPCHAR) # Note first parameter is return value

dll = ct.CDLL('./test')
# Declare function arguments and return values
dll.set_callback.argtypes = CALLBACK,
dll.set_callback.restype = None
dll.call_python_function.argtypes = PPCHAR,
dll.call_python_function.restype = None

# Set up callback function.  Note that the buffer can't go out-of-scope
# once the function returns or undefined behavior occurs, so the buffer
# is stored as an attribute of the function object so it will continue
# to exist.  A global variable would work, too.
@CALLBACK
def my_function(pp):
    my_function.buffer = ct.create_string_buffer(b'Hi From Python')
    pp[0] = my_function.buffer  # [0] dereferences char** so can assign char*

dll.set_callback(my_function)
p = PCHAR()
dll.call_python_function(ct.byref(p))
# Cast to a `c_char_p` to access `.value` and get a bytes object
# up to the terminating null.
print(ct.cast(p, ct.c_char_p).value)

输出量:

Hi From Python
b'Hi From Python'

相关问题