Python如何通过SWIG从C++获取二进制数据(char*)?

4
我是使用SWIG在Python中调用C++函数的,现在遇到了一个问题。当我将char *从C++传递到Python时,Python会截断char *。
例如:

example.h:

char * fun()
{
    return "abc\0de";
}

现在在Python中,我们调用example.fun()时,它只会打印"abc"而不是"abc\0de",'\0'后面的数据被Python删除了。
我想从C++中的fun()获取所有字符(它是一个可能包含'\0'的二进制数据),欢迎任何建议。

文档中已经很好地介绍了将二进制数据传递给C/C++的情况。(据我所知,您提出的问题没有得到充分解答)。http://www.swig.org/Doc3.0/Library.html#Library_nn10 - Bjorn Roche
3个回答

8
首先,如果你处理的是二进制数据,就不应该使用 char *(swig会认为它们是普通字符串)。相反,你应该使用 void *。swig提供了一个名为'cdata.i'的模块 - 你需要在接口定义文件中包含它。
一旦你包含了它,在此基础上,它提供了两个函数-cdata()memmove()
  • cdata()函数可以将给定的 void *类型及其长度的二进制数据转换为目标语言的字符串类型。
  • memmove()函数则相反 - 它会将给定的字符串类型(包括嵌入的 null 字节)复制到 C 的 void* 类型中。
使用这个模块处理二进制数据变得更加简单。希望这能满足您的需求。
example.i
%module example
%include "cdata.i"
%{
void *fun()
{
        return "abc\0de";
}
%}

test.py
import example
print example.cdata(example.fun(), 6)

2
你能否给一个使用memmove()的例子? - kawing-chiu

6

C/C++字符串是以NULL结尾的,这意味着第一个\0字符表示字符串的末尾。

当一个函数返回指向这样一个字符串的指针时,调用者(在这种情况下是SWIG)无法知道第一个\0之后是否还有更多数据,因此您只能获取第一部分。

因此,首先要做的事情是改变您的C函数,不仅返回字符串,而且还返回其长度。由于只能有一个返回值,我们将使用指针参数代替。

void fun(char** s, int *sz)
{
    *s = "abc\0de";
    *sz = 6;
}

SWIG文档建议使用cstring.i来封装此类函数。特别地,最后一个宏正好满足您的需求。
%cstring_output_allocate_size(parm, szparm, release)

阅读文档以学习如何使用它。


抱歉我的英语不好(哈哈,我是中国人),感谢您帮助我解决了一个困扰我整整一周的问题。非常感谢~~~ - kaitian521

0

请参阅文档中的8.3 C字符串处理

还可以从文档中了解:

char *数据类型被处理为以NULL结尾的ASCII字符串。 SWIG将其映射到目标脚本语言中的8位字符字符串。在将它们传递到C / C ++之前,SWIG将目标语言中的字符字符串转换为NULL终止字符串。这些字符串的默认处理方式不允许它们具有嵌入式NULL字节。因此,char *数据类型通常不适用于传递二进制数据。但是,可以通过定义SWIG类型映射来更改此行为。有关详细信息,请参见类型映射章节。


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