可以通过ctypes传递字符串引用吗?
抱歉,我一般很难看懂现在的ctypes文档...
假设我有一个C语言的函数,它需要一个const char *
类型的指针。我知道这个函数不会修改传入的字符串,也不会在函数调用结束后保留对它的引用,那么直接把Python字符串的字节传给这个指针其实是很合理的。
ctypes能做到这一点吗,还是说根本不支持?我真的需要用create_string_buffer
来创建一个字符串缓冲区,然后把我的字符串复制到里面吗?
2 个回答
6
类型 ctypes.c_char_p 表示一个以零结尾的字符串。也就是说,如果一个函数需要一个 const char* 类型的参数,你可以直接把一个 Python 字符串传给它,函数会接收到一个以零结尾的字符串版本。
这是一个 Windows 示例 DLL:
#include <string.h>
__declspec(dllexport) char* func(char* a,size_t len,const char* b)
{
if(strlen(b) * 2 >= len)
return NULL;
strcpy_s(a,len,b);
strcat_s(a,len,b);
return a;
}
Python 代码:
Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes import *
>>> x=CDLL('x')
>>> x.func.restype=c_char_p
>>> x.func.argtypes=[c_char_p,c_int,c_char_p]
>>> s=create_string_buffer(10)
>>> x.func(s,len(s),'abcd')
'abcdabcd'
>>>
18
给指针类型的变量,比如 c_char_p、c_wchar_p 和 c_void_p 赋新值时,其实是改变了它们指向的内存地址,而不是内存块里的内容(当然不是,因为 Python 的字符串是不可变的)。
>>> s = "Hello, World" >>> c_s = c_char_p(s) >>> print c_s c_char_p('Hello, World') >>> c_s.value = "Hi, there" >>> print c_s c_char_p('Hi, there') >>> print s # first string is unchanged Hello, World >>>
不过,你要小心,不要把这些指针传给那些期待可变内存的函数。如果你需要可变的内存块,ctypes 提供了一个 create_string_buffer 函数,可以用不同的方式来创建这些内存块。如果你想访问当前内存块的内容,可以用 raw 属性来获取(或者修改),如果你想把它当成以 NUL 结尾的字符串来使用,就用 string 属性:
这是 ctypes 教程里的内容。我理解的是,只有当函数需要处理 const char*
类型时,传入 Python 字符串才是有效的。要记住,它不会有 NUL 结尾。
我建议你还是使用 create_string_buffer
。