Hi,
I've spent many many frustrating hours trying to talk to a C struct using the FFI. Looking around at other examples, there seem to be many ways of doing this..., but none of them worked for me. In the end I wrote a short example shown below that appears to work. It relies on all the heavy lifting being done in C and just simple wrappers being written in Scheme. As written, I believe it makes Scheme and C share the same struct, no copies being taken (this is crucial for me, as the C code will alter the C struct and likewise my Scheme code will alter it too). Before I go too far with this approach, I just want to check that it is memory safe.
Here it is:
; ;Example where Gambit Scheme and C are sharing the SAME struct in memory using a pointer. ; (c-declare #<<end-of-c-declare typedef struct { int x; int y; } Cstruct;
Cstruct* make_point( int x, int y ) { Cstruct* p = (Cstruct*) malloc(sizeof(Cstruct)); p->x = x; p->y = y; return p; }
int point_x( Cstruct* p ) { return p->x; } int point_y( Cstruct* p ) { return p->y; }
//if you create new memory using malloc you must free it again when you've finished to avoid a dangling pointer memory leak void free_point( Cstruct* p ){free(p);}
end-of-c-declare )
(c-define-type Sstruct* (pointer "Cstruct"))
(define make-point (c-lambda (int int) Sstruct* "make_point")) (define free-point (c-lambda (Sstruct*) void "free_point")) (define point-x (c-lambda (Sstruct*) int "point_x")) (define point-y (c-lambda (Sstruct*) int "point_y"))
(define SchemeStruct (make-point 12345 6789)) (println "p->x in C struct holds the value " (point-x SchemeStruct)) (println "p->y in C struct holds the value " (point-y SchemeStruct)) (free-point SchemeStruct); included for completeness, but not needed because program is ending anyway in this example
Afficher les réponses par date
On 2013-04-22, at 5:37 AM, sales.creditscore@creditscore.co.nz wrote:
Hi,
I've spent many many frustrating hours trying to talk to a C struct using the FFI. Looking around at other examples, there seem to be many ways of doing this..., but none of them worked for me. In the end I wrote a short example shown below that appears to work. It relies on all the heavy lifting being done in C and just simple wrappers being written in Scheme. As written, I believe it makes Scheme and C share the same struct, no copies being taken (this is crucial for me, as the C code will alter the C struct and likewise my Scheme code will alter it too). Before I go too far with this approach, I just want to check that it is memory safe.
As far as I can tell it is memory safe. However, it might be simpler to put your free_point function as a release function on the Sstruct* foreign type. That way the free_point function will be called by the Gambit garbage collector when the Scheme program no longer has a reference to a given structure. If it is possible for your C code to keep pointers to your structure, then it will be convenient to use ___alloc_rc instead of malloc, that way you can increment the reference count in that structure to prevent the garbage collector from freeing the structure.
All of these issues can be abstracted in a macro for defining foreign structures. This is explained in the following message:
https://mercure.iro.umontreal.ca/pipermail/gambit-list/2009-May/003475.html
Marc