SWIG:将Python String传递给void指针类型的参数

时间:2016-12-13 22:20:52

标签: python-2.7 swig

我开始玩SWIG,所以我可以在Python中使用C库。我有这段代码,我将Python字符串传递给C函数,该函数需要" void *"

example.h文件:

Google Play savegames

example.c:

char test(void *buf);

的Python:

char test(void *buf) {
    char *c = (char*)buf;
    return *c;
}

当我运行它时,我收到以下错误:

import example
buf = "hello"
example.test(buf)

然而,当我改变" void *"参数到" char *",它似乎工作。我觉得有点困惑" void *"匹配任何类型的指针。无论如何,我挖了一遍并遇到了ctypes库并将其转换为c_void_p(Python: converting strings for use with ctypes.c_void_p())。这对我来说似乎没什么用。

作为一个解决方法,我在swig文件中创建了一个包装器:

TypeError: in method 'test', argument 1 of type 'void *'

这似乎有效。但是,我想知道是否有人可以解释为什么ctypes方法不起作用。如果我使用ctypes方法完全不合适,是否有比创建内联包装更合适的方法?

谢谢你们!

1 个答案:

答案 0 :(得分:1)

您的内联包装器方法是一种合理的通用方法,可以解决不太直接可用的函数。通常,SWIG会尝试模仿目标语言中C或C ++的行为。在这种情况下,虽然你观察到它不是那么做。我认为这样做的原因有两个:首先,在SWIG支持的某些语言(例如Java)中,如何做到这一点并不明显。其次,即使你可以在Python中做一些适用于这个特定情况的事情void*对C程序员来说是非常模糊的,没有关于如何解释/使用它的进一步指导。这里C和Python之间也存在不匹配 - 字符串在Python中是引用计数和不可变的,因此很容易陷入Python行为以对Python程序员来说完全不明显的方式中断的情况。

使用ctypes执行强制转换并不是一个真正可行的解决方案,SWIG和ctypes在包装事物和输入参数方面有着截然不同的方法。 (如果你很好奇,我只是在他们之间写了一个公平的detailed answer looking at interpoerability

一般情况下的另一个选项是用户%include <cpointer.i>为您生成一些代码以进行转换/转换,例如:

%pointer_cast(type1, type2, name)

但是在这种情况下,由于您使用的是char*,因此第一个备注文档中的注释适用:

  

注意:这些宏都不能用于安全地处理字符串   (char *或char **)。

     

注意:使用简单指针时,通常可以使用类型映射   提供更加无缝的操作。

总的来说,我赞成第二个注释所提出的观点,即通过做一些工作(例如%inline来提供重载)可以提供更直观的行为。因此,在您的特定情况下,我建议的唯一更改是使用%rename(test) test_wrapper;使其成为Python内部的重载。 (如果是C ++而不是C,那么你可以将其作为C ++中的重载来实现)