使用ctypes将python字符串对象转换为c char*

39
我想使用ctypes从Python(3.2)发送2个字符串到C。这是我在我的树莓派上进行的项目的一小部分。为测试C函数是否正确接收了字符串,我将其中一个放置在文本文件中。 Python代码:
string1 = "my string 1"
string2 = "my string 2"

# create byte objects from the strings
b_string1 = string1.encode('utf-8')
b_string2 = string2.encode('utf-8')

# send strings to c function
my_c_function(ctypes.create_string_buffer(b_string1),
              ctypes.create_string_buffer(b_string2))

C 代码

void my_c_function(const char* str1, const char* str2)
{
    // Test if string is correct
    FILE *fp = fopen("//home//pi//Desktop//out.txt", "w");
    if (fp != NULL)
    {
        fputs(str1, fp);
        fclose(fp);
    }

    // Do something with strings..
}

问题

文本文件中只有字符串的第一个字母。

我尝试了很多种方法来使用ctypes转换Python字符串对象。

  • ctypes.c_char_p
  • ctypes.c_wchar_p
  • ctypes.create_string_buffer

但是这些转换都会报错,提示"wrong type"或者"bytes or integer address expected instead of str instance"。

希望有人能告诉我出了什么问题。提前致谢。


8
设置 my_c_function.argtypes = [ctypes.c_char_p, ctypes.c_char_p]。由于参数是 const,因此可以简单地调用 my_c_function(b_string1, b_string2) - Eryk Sun
2
请注意,字面上的反斜杠字符需要转义为"\\",但正斜杠则不需要。只需写成"/home/pi/Desktop/out.txt"即可。 - Eryk Sun
1
@eryksun谢谢您的回复。现在它可以工作了,我完全忘记我仍然将argtypes设置为c_wchar_p。关于斜杠,我总是混淆它们。 - LittleOne
5
只有在函数修改字符串时才使用buf = ctypes.create_string_buffer(bstr),其等价于buf = (ctypes.c_char * (len(bstr) + 1))(); buf.value = bstr - Eryk Sun
3个回答

49
感谢Eryksun提供的解决方案: Python代码
string1 = "my string 1"
string2 = "my string 2"

# create byte objects from the strings
b_string1 = string1.encode('utf-8')
b_string2 = string2.encode('utf-8')

# send strings to c function
my_c_function.argtypes = [ctypes.c_char_p, ctypes.char_p]
my_c_function(b_string1, b_string2)

2
我的C函数.argtypes = [ctypes.c_char_p, ctypes.char_p],你的意思是my_c_function.argtypes = [ctypes.c_char_p, ctypes.char_p](注意使用.而不是_)? - hola
2
哈哈,五年后有人注意到或感到困扰并指出了它。谢谢你,我已经在答案中进行了编辑。 - LittleOne
3
你知道,强迫症吗! - hola
1
my_c_function.argtypes = [ctypes.c_char_p, ctypes.char_p] 您是指 my_c_function.argtypes = [ctypes.c_char_p, ctypes.c_char_p] 吗? - a11apurva

20

我认为你只需要使用c_char_p()而不是create_string_buffer()。

string1 = "my string 1"
string2 = "my string 2"

# create byte objects from the strings
b_string1 = string1.encode('utf-8')
b_string2 = string2.encode('utf-8')

# send strings to c function
my_c_function(ctypes.c_char_p(b_string1),
              ctypes.c_char_p(b_string2))

如果您需要可变字符串,则使用 create_string_buffer() 并使用 ctypes.cast() 将其转换为 c_char_p。


1

你有考虑使用SWIG吗?我自己没有试过,但这就是它的样子,而且不需要改变你的C源码:

/*mymodule.i*/

%module mymodule
extern void my_c_function(const char* str1, const char* str2);

这将使你的Python源代码更简单(跳过编译):
import mymodule

string1 = "my string 1"
string2 = "my string 2"
my_c_function(string1, string2)

请注意,如果您的源文件已经是UTF-8,则我不确定.encode('utf-8')是否必要。

2
对于Python 3,请记得使用swig的-py3选项。包装器将Python 3字符串编码为UTF-8,使用PyUnicode_AsUTF8String,然后使用PyBytes_AsStringAndSize。传递bytes会引发TypeError - Eryk Sun

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