Wrapping C function with pointer arguments using SWIG
Question:
I’m trying to use SWIG to wrap an existing C library for use in Python. I’m running swig 2.0.10 on Windows XP with Python 2.7.4. The problem I’m encountering is that I’m unable to call a wrapped C function that has a pointer to an int as an argument which is where the function result is to be stored. I’ve distilled the problem into the follow example code:
The C function in convert.c:
#include <stdio.h>
#include "convert.h"
#include <stdlib.h>
int convert(char *s, int *i)
{
*i = atoi(s);
return 0;
}
The header file in convert.h
#ifndef _convert_h_
#define _convert_h_
int convert(char *, int *);
#endif
The swig interface file in convert.i
/* File : convert.i */
%module convert
%{
#include "convert.h"
%}
%include "convert.h"
All of this is being built into a .pyd file using Visual C++ 2010. When the build is complete, I’m left with two files: convert.py and _convert.pyd in the build directory. I open a command window in this directory and start python session and enter the following:
Python 2.7.4 (default, Apr 6 2013, 19:54:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes import *
>>> import convert
>>> dir(convert)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '_convert', '_newclass', '_object', '_swig_getattr', '_swig_property', '_swig_repr', '_swig_setattr', '_swig_setattr_nondynamic', 'convert']
>>> i = c_int()
>>> i
c_long(0)
>>> convert.convert('1234', byref(i))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: in method 'convert', argument 2 of type 'int *'
Why is my pointer object being rejected? What should I do to make this work?
Answers:
SWIG
and ctypes
are different libraries, so you can’t pass ctypes objects directly to SWIG-wrapped functions.
In SWIG, the %apply
command can apply typemaps to common parameter types to configure them as INPUT
, INOUT
, or OUTPUT
parameters. Try the following:
%module convert
%{
#include "convert.h"
%}
%apply int *OUTPUT {int*};
%include "convert.h"
Python will no longer require the parameter on input, and will change the output of the function to be a tuple of the return value and any INOUT
or OUTPUT
parameters:
>>> import convert
>>> convert.convert('123')
[0, 123]
Note that parameters beyond the POD (plain old data) types usually require writing your own typemaps. Consult the SWIG Documentation for more details.
I’m trying to use SWIG to wrap an existing C library for use in Python. I’m running swig 2.0.10 on Windows XP with Python 2.7.4. The problem I’m encountering is that I’m unable to call a wrapped C function that has a pointer to an int as an argument which is where the function result is to be stored. I’ve distilled the problem into the follow example code:
The C function in convert.c:
#include <stdio.h>
#include "convert.h"
#include <stdlib.h>
int convert(char *s, int *i)
{
*i = atoi(s);
return 0;
}
The header file in convert.h
#ifndef _convert_h_
#define _convert_h_
int convert(char *, int *);
#endif
The swig interface file in convert.i
/* File : convert.i */
%module convert
%{
#include "convert.h"
%}
%include "convert.h"
All of this is being built into a .pyd file using Visual C++ 2010. When the build is complete, I’m left with two files: convert.py and _convert.pyd in the build directory. I open a command window in this directory and start python session and enter the following:
Python 2.7.4 (default, Apr 6 2013, 19:54:46) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from ctypes import *
>>> import convert
>>> dir(convert)
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '_convert', '_newclass', '_object', '_swig_getattr', '_swig_property', '_swig_repr', '_swig_setattr', '_swig_setattr_nondynamic', 'convert']
>>> i = c_int()
>>> i
c_long(0)
>>> convert.convert('1234', byref(i))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: in method 'convert', argument 2 of type 'int *'
Why is my pointer object being rejected? What should I do to make this work?
SWIG
and ctypes
are different libraries, so you can’t pass ctypes objects directly to SWIG-wrapped functions.
In SWIG, the %apply
command can apply typemaps to common parameter types to configure them as INPUT
, INOUT
, or OUTPUT
parameters. Try the following:
%module convert
%{
#include "convert.h"
%}
%apply int *OUTPUT {int*};
%include "convert.h"
Python will no longer require the parameter on input, and will change the output of the function to be a tuple of the return value and any INOUT
or OUTPUT
parameters:
>>> import convert
>>> convert.convert('123')
[0, 123]
Note that parameters beyond the POD (plain old data) types usually require writing your own typemaps. Consult the SWIG Documentation for more details.