如何使用 ctypes.create_string_buffer 将其作为 C 函数的 char * 参数传递?
How do I use ctypes.create_string_buffer to pass it as a char * argument for a C function?
我有一个 C/C++ dll 函数:
int get_camera_info(char * description, char * serial_number, char * manufacturer)
此函数接受参数并修改它们,以便您可以打印它们。我正在尝试通过 ctypes
使用来自 Python 的这个 DLL。我想我需要使用 ctypes.create_string_buffer
来创建一个空缓冲区,以便我有一个可变对象。但是,我该怎么做才能将其作为参数传递然后检索数据?
我需要使用 cast(buffer_object, c_char_p_object)
吗?这与最初创建和传递 c_char_p
对象有什么不同?我不太了解 C/C++,但也许我应该使用 ctypes.POINTER
.
我的问题是,在将 c_char_p
类型的对象作为参数传递后,出现错误:OSError: exception: access violation reading 0x00000000
.
如果您需要任何帮助来理解我的问题,尽管问。或者,如果您认为我最好使用 cppyy 之类的东西,那么我也需要帮助。 :)
这是基础知识。虽然在这种情况下没有严格要求,但正确设置 .argtypes
和 .restype
有助于 ctypes
正确编组参数并检测错误传递的参数。
类似于将数组传递给C函数,create_string_buffer
returns一个c_char_Array_array_<i>size</i>
对象,但它被编组为指向它的第一个元素 (c_char_p
) 的指针,因此它符合 .argtypes
赋值。
如果没有 .argtypes
赋值,传递不正确的内容(例如 int
或 create_unicode_buffer()
数组将会崩溃或产生错误结果。但正确定义它会捕获这些错误并引发异常。
test.c
#include <string.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API int get_camera_info(char * description, char * serial_number, char * manufacturer)
{
strcpy(description, "Description");
strcpy(serial_number, "12345678");
strcpy(manufacturer, "Manufacturer");
return 1;
}
test.py
from ctypes import *
MAX_STR = 256 # docs better say how big the buffers are required to be.
# int get_camera_info(char * description, char * serial_number, char * manufacturer)
dll = CDLL('./test')
dll.get_camera_info.argtypes = c_char_p,c_char_p,c_char_p
dll.get_camera_info.restype = c_int
desc = create_string_buffer(MAX_STR)
sn = create_string_buffer(MAX_STR)
mfg = create_string_buffer(MAX_STR)
ret = dll.get_camera_info(desc,sn,mfg)
print(desc.value.decode(),sn.value.decode(),mfg.value.decode())
输出:
Description 12345678 Manufacturer
注意.value
returns 缓冲区开头的一个字节串,直到第一个空字节独占。 .raw
将转储包含缓冲区每个字节的字节字符串。 .decode()
使用 UTF-8 作为默认编码将字节字符串转换为 Unicode 字符串。
我有一个 C/C++ dll 函数:
int get_camera_info(char * description, char * serial_number, char * manufacturer)
此函数接受参数并修改它们,以便您可以打印它们。我正在尝试通过 ctypes
使用来自 Python 的这个 DLL。我想我需要使用 ctypes.create_string_buffer
来创建一个空缓冲区,以便我有一个可变对象。但是,我该怎么做才能将其作为参数传递然后检索数据?
我需要使用 cast(buffer_object, c_char_p_object)
吗?这与最初创建和传递 c_char_p
对象有什么不同?我不太了解 C/C++,但也许我应该使用 ctypes.POINTER
.
我的问题是,在将 c_char_p
类型的对象作为参数传递后,出现错误:OSError: exception: access violation reading 0x00000000
.
如果您需要任何帮助来理解我的问题,尽管问。或者,如果您认为我最好使用 cppyy 之类的东西,那么我也需要帮助。 :)
这是基础知识。虽然在这种情况下没有严格要求,但正确设置 .argtypes
和 .restype
有助于 ctypes
正确编组参数并检测错误传递的参数。
类似于将数组传递给C函数,create_string_buffer
returns一个c_char_Array_array_<i>size</i>
对象,但它被编组为指向它的第一个元素 (c_char_p
) 的指针,因此它符合 .argtypes
赋值。
如果没有 .argtypes
赋值,传递不正确的内容(例如 int
或 create_unicode_buffer()
数组将会崩溃或产生错误结果。但正确定义它会捕获这些错误并引发异常。
test.c
#include <string.h>
#ifdef _WIN32
# define API __declspec(dllexport)
#else
# define API
#endif
API int get_camera_info(char * description, char * serial_number, char * manufacturer)
{
strcpy(description, "Description");
strcpy(serial_number, "12345678");
strcpy(manufacturer, "Manufacturer");
return 1;
}
test.py
from ctypes import *
MAX_STR = 256 # docs better say how big the buffers are required to be.
# int get_camera_info(char * description, char * serial_number, char * manufacturer)
dll = CDLL('./test')
dll.get_camera_info.argtypes = c_char_p,c_char_p,c_char_p
dll.get_camera_info.restype = c_int
desc = create_string_buffer(MAX_STR)
sn = create_string_buffer(MAX_STR)
mfg = create_string_buffer(MAX_STR)
ret = dll.get_camera_info(desc,sn,mfg)
print(desc.value.decode(),sn.value.decode(),mfg.value.decode())
输出:
Description 12345678 Manufacturer
注意.value
returns 缓冲区开头的一个字节串,直到第一个空字节独占。 .raw
将转储包含缓冲区每个字节的字节字符串。 .decode()
使用 UTF-8 作为默认编码将字节字符串转换为 Unicode 字符串。