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

发布于 2024-12-16 11:16:10 字数 355 浏览 0 评论 0原文

我正在通过 SWIG 在 Python 中使用 C++ 函数,现在遇到了问题。 当我将 char * 从 C++ 传递到 Python 时,char * 被 Python 截断。

例如:

example.h:

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

现在在Python中,我们调用 示例.fun() 它只打印 “abc” 而不是 “abc\0de” '\0'后面的数据被Python删除。

我想从 C++ 中的 fun() 获取所有字符(它是可以包含 '\0' 的二进制数据), 如有任何建议,我们将不胜感激

I am using C++ functions in Python by SWIG,and I met a problem now.
When I pass a char * from C++ to Python, the char * is truncted by Python.

For example:

example.h:

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

now in Python,we call
example.fun()
it only print
"abc"
instead of
"abc\0de"
the data behind '\0' is deleted by Python.

I want to get all the chars(it is a binary data that can contains '\0') from fun() in C++,
and any advise is appreciated

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

月朦胧 2024-12-23 11:16:10

首先,如果您正在处理二进制数据,则不应使用 char *(swig 认为它们是普通字符串)。相反,您应该使用void *。 swig 提供了一个名为“cdata.i”的模块 -
您应该将其包含在接口定义文件中。

一旦包含它,它就会提供两个函数 - cdata()memmove()

  • 给定一个void *和二进制数据的长度,cdata()将其转换为目标语言的字符串类型。
  • memmove() 则相反 - 给定一个字符串类型,它会将字符串的内容(包括嵌入的空字节)复制到 C void* 类型中。

使用此模块处理二进制数据变得更加简单。我希望这就是您所需要的。

example.i
%module example
%include "cdata.i"
%{
void *fun()
{
        return "abc\0de";
}
%}

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

First of all, you should not use char * if you are dealing with binary data (swig thinks that they are normal strings). Instead you should use void *. swig provides a module named 'cdata.i' -
you should include this in the interface definition file.

Once you include this, it gives two functions - cdata() and memmove().

  • Given a void * and the length of the binary data, cdata() converts it into a string type of the target language.
  • memmove() does the reverse - given a string type, it will copy the contents of the string(including embedded null bytes) into the C void* type.

Handling binary data becomes much simpler with this module. I hope this is what you need.

example.i
%module example
%include "cdata.i"
%{
void *fun()
{
        return "abc\0de";
}
%}

test.py
import example
print example.cdata(example.fun(), 6)
撩心不撩汉 2024-12-23 11:16:10

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)

阅读文档以了解如何使用它。

C/C++ strings are NULL-terminated which means that the first \0 character denotes the end of the string.

When a function returns a pointer to such a string, the caller (SWIG in this case) has no way of knowing if there is more data after the first \0 so that's why you only get the first part.

So first thing to do is to change your C function to return not just the string but its length as well. Since there can be only one return value we'll use pointer arguments instead.

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

The SWIG docs suggest using the cstring.i library to wrap such functions. In particullar, the last macro does exactly what you need.

%cstring_output_allocate_size(parm, szparm, release)

Read the docs to learn how to use it.

风吹雨成花 2024-12-23 11:16:10

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

同样来自文档

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

See 8.3 C String Handling in the documentation.

Also from the documentation:

The char * datatype is handled as a NULL-terminated ASCII string. SWIG
maps this into a 8-bit character string in the target scripting
language. SWIG converts character strings in the target language to
NULL terminated strings before passing them into C/C++. The default
handling of these strings does not allow them to have embedded NULL
bytes. Therefore, the char * datatype is not generally suitable for
passing binary data. However, it is possible to change this behavior
by defining a SWIG typemap. See the chapter on Typemaps for details
about this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文