0

I'm having trouble with swig and char ** as pointer to a variable char * (not as a list of char *!!!). I couldn't find out a way to wrap the pointer to a char *.

The aim is to write the result of the concatenation in the char * referenced by the pointer.

The following is my code:

File pointers.cpp:

#include "pointers.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

void conc(char *str1, char *str2, char **res){
  char *aux = (char *)malloc(strlen(str1)+strlen(str2)+1);
  strcpy(aux,str1);
  strcat(aux,str2);
  strcpy(*res,aux);
  free(aux);
}

File pointers.h

void conc(char *str1, char *str2, char **res)

File pointers.i

%module pointers
%{
#define SWIG_FILE_WITH_INIT
#include "pointers.h"
%}

%include "typemaps.i"
%include "cpointer.i"
%include "cstring.i"

%pointer_functions(char *, charp);
extern void conc(char *str1, char *str2, char **res);

File setup.py:

from distutils.core import setup, Extension


pointers_module = Extension('_pointers',
                       sources=['pointers_wrap.cxx', 'pointers.cpp'],
                       )

setup (name = 'pointers',
   version = '0.1',
   author      = "SWIG Docs",
   description = """Simple swig example from docs""",
   ext_modules = [pointers_module],
   py_modules = ["pointers"],
   )

Finally, the python main:

import pointers

result = new_charp()
pointers.conc("Hello ","World!", result);
print(result)
delete_charp(result)

And all of them are compiled with terminal commands:

swig -c++ -python pointers.i
python setup.py build_ext --inplace 

But the compiler return error:

pointers_wrap.cxx: In function ‘char** copy_charp(char*)’:
pointers_wrap.cxx:3124:58: error: invalid static_cast from type ‘char*’ to            
type ‘const char*&’ return (new char *(static_cast< const char *& >(value)));
                                                                         ^
error: command 'gcc' failed with exit status 1

Any helps?

[UPDATE TO THE QUESTION]

As suggested by @MarkTolonen I tried to change the pointers.i file in the following way:

New file pointers.i:

%module pointers

%{
#include "pointers.h"
%}

// This input typemap declares that char** requires no input parameter.
// Instead, the address of a local char* is used to call the function.
%typemap(in,numinputs=0) char** (char* tmp) %{
  $1 = &tmp;
%}

// After the function is called, the char** parameter contains a malloc'ed char* pointer.
// Construct a Python Unicode object (I'm using Python 3) and append it to
// any existing return value for the wrapper.
%typemap(argout) char** %{
  PyObject *obj = PyUnicode_FromString(*$1);
  $result = SWIG_Python_AppendOutput($result,obj);
%}

// The malloc'ed pointer is no longer needed, so make sure it is freed.
%typemap(freearg) char** %{
  free(*$1);
%}

// Now that the typemap exists, let swig wrap the header.
%include "pointers.h"

Compiling with:

swig -c++ -python pointers.i
g++ --std=c++11 -fPIC -c pointers.cpp
g++ --std=c++11 -fPIC -c pointers_wrap.cxx -I/usr/local/include/python3.6m

And then I got the error:

In function ‘PyObject* _wrap_conc(PyObject*, PyObject*):`
pointers_wrap.cxx:3618:1: error: jump to label ‘fail’ [-fpermissive]
fail:
pointers_wrap.cxx:1222:49: note:   from here
 #define SWIG_fail                  goto fail

pointers_wrap.cxx:2999:68: note: in expansion of macro ‘SWIG_fail’
 #define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0)
pointers_wrap.cxx:3603:5: note: in expansion of macro ‘SWIG_exception_fail’
 SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "conc" "', argument " "2"" of type '" "char *""'");

pointers_wrap.cxx:3609:8: note:   crosses initialization of ‘_object* obj’
 auto obj = PyUnicode_FromString(*arg3);
pointers_wrap.cxx:3618:1: error: jump to label ‘fail’ [-fpermissive]
fail:

pointers_wrap.cxx:1222:49: note:   from here
 #define SWIG_fail                     goto fail
pointers_wrap.cxx:2999:68: note: in expansion of macro ‘SWIG_fail’
 #define SWIG_exception_fail(code, msg) do { SWIG_Error(code, msg); SWIG_fail; } while(0)
pointers_wrap.cxx:3598:5: note: in expansion of macro ‘SWIG_exception_fail’
 SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "conc" "', argument " "1"" of type '" "char *""'");

pointers_wrap.cxx:3609:8: note:   crosses initialization of ‘_object* obj’
 auto obj = PyUnicode_FromString(*arg3);

pointers_wrap.cxx:3618:1: error: jump to label ‘fail’ [-fpermissive]
fail:
pointers_wrap.cxx:1222:49: note:   from here
 #define SWIG_fail                   goto fail
pointers_wrap.cxx:3595:62: note: in expansion of macro ‘SWIG_fail’
 if (!PyArg_ParseTuple(args,(char *)"OO:conc",&obj0,&obj1)) SWIG_fail;
pointers_wrap.cxx:3609:8: note:   crosses initialization of ‘_object* obj’
 auto obj = PyUnicode_FromString(*arg3);

It works on this windows OS but not on my ubuntu. Can anyone tell how to deal with it. I really don't know how resolve my pointers problem.

lorsp000
  • 23
  • 5
  • where is pointers_wrap.cxx coming from? >3k lines in a single file makes me dizzy even without seeing the file – 463035818_is_not_an_ai Oct 20 '17 at 10:10
  • yeah, it's created running the file setup.py. It's the automatic created file by swig to build the wrapper file. And it's needed in the creation of the swig module. – lorsp000 Oct 20 '17 at 12:56

1 Answers1

0

From the SWIG 3.0 documentation, near the end of §9.2.1 cpointer.i:

Note: None of these macros can be used to safely work with strings (char * or char **).

So you will have to resort to typemaps. Below is an example:

pointers.cpp

I had to change your source slightly. A char** argument should return the allocated pointer, and not free it:

#include <string.h>
#include <stdlib.h>
#include "pointers.h"

void conc(char *str1, char *str2, char **res){
  *res = (char *)malloc(strlen(str1)+strlen(str2)+1);
  strcpy(*res,str1);
  strcat(*res,str2);
}

pointers.h

void conc(char *str1, char *str2, char **res);

pointers.i

This version of the swig file declares the typemaps to handle the char** output argument.

%module pointers

%{
#include "pointers.h"
%}

// This input typemap declares that char** requires no input parameter.
// Instead, the address of a local char* is used to call the function.
%typemap(in,numinputs=0) char** (char* tmp) %{
    $1 = &tmp;
%}

// After the function is called, the char** parameter contains a malloc'ed char* pointer.
// Construct a Python Unicode object (I'm using Python 3) and append it to
// any existing return value for the wrapper.
%typemap(argout) char** (PyObject* obj) %{
    obj = PyUnicode_FromString(*$1);
    $result = SWIG_Python_AppendOutput($result,obj);
%}

// The malloc'ed pointer is no longer needed, so make sure it is freed.
%typemap(freearg) char** %{
    free(*$1);
%}

// Now that the typemap exists, let swig wrap the header.
%include "pointers.h"

test.py

import pointers
result = pointers.conc('Hello ','World!');
print(result)

Output

Hello World!

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
  • thank you! But compiling your code, I got some errors, all referring `jump to label 'fail'` in the function `PyObject* _wrap_conc(PyObject*, PyObject*)` and a note: `crosses initialization of '_object* obj'` on `auto obj =`. Do u know why? – lorsp000 Oct 22 '17 at 13:52
  • @lorsp000 Your C++ compiler is old. Change auto to the return type of PyUnicodeFromString. I think it is PyObject*. – Mark Tolonen Oct 22 '17 at 16:19
  • I tried to change the return type, but still doesn't work. On the other hand I got a g++ 6.3.0 version, is it too old for PyUnicodeFromString? – lorsp000 Oct 23 '17 at 07:50
  • It's not the c++ compiler, I've just run it with command --str=c++11. – lorsp000 Oct 23 '17 at 08:26
  • I've explained the problem better in a new answer. – lorsp000 Oct 23 '17 at 09:23
  • @lorsp000 I made a change to `pointers.i` that might fix the problem. Your compiler is indicating that the initialization of `obj` can be skipped. I changed the way it was declared so SWIG will declare the variable at the top of the wrapper instead of inline. – Mark Tolonen Oct 23 '17 at 16:00
  • Once again thks @MarkTolonen. Now the module compiles. But using it, in particular when the code compute `strcat(*res,str2)`, I got a `Segmentation Fault (core dumped)` error. Am I calling the variable wrong? Sorry I now I'm asking u too much...but I'm really stuck – lorsp000 Oct 24 '17 at 09:15
  • Sorry @MarkTolonen! The code works!! thank you very much. – lorsp000 Oct 24 '17 at 09:57