通过ctypes是否可能通过引用传递Python字符串?

7

很抱歉,我通常很难阅读当前的ctypes文档...

如果我有一个接受const char *指针的C函数,并且我知道它既不会修改传入的字符串,也不会在函数调用之后保留对它的引用,那么将python字符串的字节直接传递给指针真的是很合理的。

ctypes能做到这一点吗?还是说根本不支持?我真的需要create_string_buffer并将我的字符串复制到其中吗?

2个回答

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教程所说,你需要小心,不要将它们传递给期望可变内存指针的函数。如果你需要可变内存块,ctypes有一个create_string_buffer函数可以以各种方式创建这些块。如果你想将其作为以NUL结尾的字符串访问,可以使用raw属性访问(或更改)当前内存块内容,使用string属性。

由此可知,仅当函数能够使用const char*时,才能使用python字符串进行传递,但请注意,它不会有空终止符。

无论如何,我建议还是使用create_string_buffer


谢谢,你是完全正确的。我甚至还模糊地记得以前读过这个。我讨厌ctypes文档在教程中放置关键信息。 - porgarmingduod
我明白你的意思。Python文档非常好,除非你需要查找某些内容。那么你就需要阅读与你想要做的事情相关的所有内容。但是我必须强调一下,你传入的字符串将不会以空字符结尾。因此,请不要在它们上面使用任何std::string或string.h函数。 - bryanegr
Python字符串传递给ctypes将会以空字符结尾。将Python字符串传递给接受c_char_p类型的函数是有效的。 - Mark Tolonen
只有通过create_string_buffer函数传递的字符串才会以null结尾。Python字符串没有null结尾。 - bryanegr
仔细查看ctypes教程中的所有示例。这些示例使用Python字符串调用printfstrchr等函数,并且它们以空字符结尾。只有在需要可变字符串时才需要使用create_string_buffer - Mark Tolonen
@bryanegr 正在引用特定的内容 ctypes section 15.17.1.4 - CivFan

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'
>>>

2
Python文档中提到:“None、整数、长整型、字节串和Unicode字符串是唯一可以直接用作这些函数调用参数的本地Python对象。...字节串和Unicode字符串作为指向包含它们数据的内存块的指针传递(char *或wchar_t *)。在调用函数部分,在基本数据类型之前。” - Mark Mikofski
1
Python C API函数PyString_AsString的Python文档:返回字符串内容的以NUL结尾的表示。指针指向字符串的内部缓冲区,而不是副本。内部字符串缓冲区是以NUL结尾的。 - Mark Tolonen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接