kaitian521
kaitian521

Reputation: 578

How Python can get binary data(char*) from C++ by SWIG?

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

Upvotes: 4

Views: 6874

Answers (3)

sunil
sunil

Reputation: 3567

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)

Upvotes: 8

codeape
codeape

Reputation: 100766

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.

Upvotes: 0

yak
yak

Reputation: 9041

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.

Upvotes: 6

Related Questions