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 将 Python 数组传递给 c++ 函数

无法确定从 SWIG(不是 ctypes)C 传递给 python 例程的正确参数

使用 SWIG 将 C++ 对象指针传递给 Python,而不是再次返回 C++

如何将复数从 python numpy 传递给 c(目前正在尝试使用 SWIG)

SWIG:如何将复数向量从 C++ 传递到 python

如何在 SWIG/Python 中将结构列表传递给 C