[Haskell-cafe] Re: How to deal with pointers to pointers in the FFI

Ben Franksen ben.franksen at online.de
Fri Oct 17 18:29:32 EDT 2008


Jefferson Heard wrote:

> I have the following functions in C:
> 
> OGRErr        OGR_G_CreateFromWkb (unsigned char *, OGRSpatialReferenceH,
> OGRGeometryH *, int)
> OGRErr        OGR_G_CreateFromWkt (char **, OGRSpatialReferenceH,
OGRGeometryH
> *)
> void  OGR_G_DestroyGeometry (OGRGeometryH)
> OGRGeometryH  OGR_G_CreateGeometry (OGRwkbGeometryType)
> 
> The normal sequence of calls is
> 
> OGRGeometryH handle = OGR_G_CreateGeometry(SOME_TYPE);
> // do stuff
> OGR_G_DestroyGeometry(handle);
> 
> OR
> 
> OGR_G_CreateFromWkb(blob, ref, &handle, 0);
> // do stuff
> OGR_G_DestroyGeometry(handle);
> 
> As you can see, in one case, I have to pass in a pointer to the
> returned handle, and not just the handle.  How can I accomplish this
> feat using a single type?
> 
> I had
> 
> data OGRGeometryH
> type Geometry = Ptr OGRGeometryH

Almost: Assuming that OGRGeometryH is some sort of pointer, e.g.

  typedef struct OGRGeometry *OGRGeometryH

you could write:

> data OGRGeometry
> type OGRGeometryH = Ptr OGRGeometry

where OGRGeometryH is the type that you API exports.

> foreign import ccall
>   oGR_G_CreateFromWkb :: ...whatever... -> Ptr OGRGeometryH -> OGRErr

Note that  Ptr OGRGeometryH  is in fact a pointer to a pointer, just as the
C type demands. When calling such a procedure you must first allocate
space. This is most elegantly done using alloca (I have added some basic
error handling, otherwise the value returned might be undefined):

> createFromWbk :: ...argtypes... -> Either OGRErr OGRGeometryH
> createFromWbk ...args... = alloca $ \ptr -> do
>   -- in this code block you can peek and poke the ptr;
>   -- space will be deallocated after block exits
>   res <- oGR_G_CreateFromWkb ...args... ptr
>   if checkResultOK res
>     then do
>       -- this can be shortened to: liftM Right $ peek ptr
>       -- or: peek ptr >>= return . Right
>       h <- peek ptr
>       return (Right h)
>     else return (Left res)

(Instead of returning an Either type you could throw exceptions, but you
didn't ask about error handling, did you ?-)

Cheers
Ben



More information about the Haskell-Cafe mailing list