Help with implementing callback functions using ctypes

jamadagni samjnaa at gmail.com
Wed May 8 07:19:07 EDT 2013


Hello. I am running Kubuntu Raring with Python 3.3.1. (I mostly don't myself use Py2.) 

I have the below C program spiro.c (obviously a simplified testcase) which I compile to a sharedlib using clang -fPIC -shared -o libspiro.so spiro.c, sudo cp to /usr/lib and am trying to call from a Python script spiro.py using ctypes. However it would seem that the first call to the callback results in a segfault. (The line before the callback is executed.) I tried debugging using gdb but perhaps because of my insufficient knowledge I couldn't find out what is causing the problem. 

I hope some of the kind knowledgeable souls here can help me out:

-- spiro.c

# include <stdbool.h>
# include <stdio.h>

typedef struct _bezctx bezctx ;
struct _bezctx {
	void ( * moveto    ) ( bezctx * bc, double x, double y, bool starts_open_path ) ;
	void ( * lineto    ) ( bezctx * bc, double x, double y ) ;
	void ( * curveto   ) ( bezctx * bc, double c1x, double c1y, double c2x, double c2y, double x, double y ) ;
    void ( * track_seg ) ( bezctx * bc, unsigned int start_node_idx ) ;
} ;

typedef struct {
	double x, y ;
	char ty ;
} spiro_cp ;
 
bool spiro_to_bezier_strict ( const spiro_cp src [], int src_len, bezctx * bc ) {
	for ( int i = 0 ; i < src_len ; ++i ) {
		const spiro_cp * p = &(src[i]) ;
		printf ( "%g %g %c\n", p->x, p->y, p->ty ) ;
		if ( i % 2 == 0 )
			bc -> moveto ( bc, p->x, p->y, i % 3 ) ;
		else
			bc -> lineto ( bc, p->x, p->y ) ;
		bc -> curveto ( bc, 233, 150, 267, 150, 300, 100 ) ;
		bc -> track_seg ( bc, i ) ;
	}
	return src_len % 2 == 0 ;
}

-- spiro.py

from ctypes import *

# incomplete struct definition needed for pointer below
class bezctx ( Structure ) : pass

# pointer to function types for callback
MoveToFnType       = CFUNCTYPE ( None, POINTER ( bezctx ), c_double, c_double, c_bool )
LineToFnType       = CFUNCTYPE ( None, POINTER ( bezctx ), c_double, c_double )
CurveToFnType      = CFUNCTYPE ( None, POINTER ( bezctx ), c_double, c_double, c_double, c_double, c_double, c_double )
TrackSegmentFnType = CFUNCTYPE ( None, POINTER ( bezctx ), c_uint )

# completing the struct definition
bezctx._fields_ = [ ( "moveto"   , MoveToFnType       ), 
                    ( "lineto"   , LineToFnType       ), 
                    ( "curveto"  , CurveToFnType      ), 
                    ( "track_seg", TrackSegmentFnType ) ]

# the python callbacks
def moveTo ( bc, x, y, startsOpenPath ) :
	print ( "moveTo", bc, x, y, startsOpenPath )
def lineTo ( bc, x, y ) :
	print ( "lineTo", bc, x, y )
def curveTo ( bc, c1x, c1y, c2x, c2y, x, y ) :
	print ( "curveTo", bc, c1x, c1y, c2x, c2y, x, y )
def trackSegment ( bc, start_node_idx ) :
	print ( "trackSegment", bc, start_node_idx )

# instance of struct
bc = bezctx ()
bc . moveto    = MoveToFnType       ( moveTo       )
bc . lineto    = LineToFnType       ( lineTo       )
bc . curveto   = CurveToFnType      ( curveTo      )
bc . track_seg = TrackSegmentFnType ( trackSegment )

# another struct
class spiro_cp ( Structure ) :
	_fields_ = [ ( "x", c_double ), ( "y", c_double ), ( "ty", c_char ) ]

# array of struct instances
srclist = [ spiro_cp ( 147, 215, b'o' ), 
            spiro_cp ( 168, 136, b'o' ), 
            spiro_cp ( 294, 184, b'[' ), 
            spiro_cp ( 381, 136, b']' ), 
            spiro_cp ( 445, 204, b'c' ), 
            spiro_cp ( 364, 235, b'c' ), 
            spiro_cp ( 266, 285, b'v' ) ]
src = ( spiro_cp * len ( srclist ) ) ( *srclist )

# open the sharedlib
libspiro = CDLL ( "libspiro.so" )
spiro_to_bezier_strict = libspiro.spiro_to_bezier_strict

# call the C function
spiro_to_bezier_strict ( src, len ( src ), bc )

-- bash session

$ python3 spiro-ctypes.py 
147 215 o
Segmentation fault (core dumped)



More information about the Python-list mailing list