SWIG:将 Python 字符串传递给 void 指针类型的参数
Posted
技术标签:
【中文标题】SWIG:将 Python 字符串传递给 void 指针类型的参数【英文标题】:SWIG: Pass Python String to argument of type void pointer 【发布时间】:2016-12-13 22:20:51 【问题描述】:我已经开始使用 SWIG,以便可以在 Python 中使用 C 库。我有这段代码,我将 Python 字符串传递给需要“void *”的 C 函数
example.h:
char test(void *buf);
example.c:
char test(void *buf)
char *c = (char*)buf;
return *c;
Python:
import example
buf = "hello"
example.test(buf)
当我运行它时,我得到以下错误:
TypeError: in method 'test', argument 1 of type 'void *'
但是,当我将“void*”参数更改为“char*”时,它似乎可以工作。我有点困惑,因为我认为“void*”匹配任何类型的指针。无论如何,我四处挖掘并发现了 ctypes 库并将其转换为 c_void_p (Python: converting strings for use with ctypes.c_void_p())。那似乎对我不起作用。
作为一种解决方法,我在我的 swig 文件中做了一个包装器:
/* File: example.i */
%module example
%include typemaps.i
%
#include "example.h"
%
%include "example.h"
%inline %
char test_wrapper(char *buf)
void *voidBuf = (void*)buf;
return test(voidBuf);
%
这似乎有效。但是,我想知道是否有人可以解释为什么 ctypes 方法不起作用。如果我对 ctypes 方法完全不满意,有没有比创建内联包装器更合适的方法?
谢谢大家!
【问题讨论】:
【参考方案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++ 中将其作为重载)
【讨论】:
以上是关于SWIG:将 Python 字符串传递给 void 指针类型的参数的主要内容,如果未能解决你的问题,请参考以下文章
无法确定从 SWIG(不是 ctypes)C 传递给 python 例程的正确参数
使用 SWIG 将 C++ 对象指针传递给 Python,而不是再次返回 C++