[Haskell-cafe] c2hs, size_t, and CSize -- argh!

John Van Enk vanenkj at gmail.com
Thu Oct 1 13:00:15 EDT 2009

Hi Duncan,

Yes, I forgot to leave out that I'd like to see 'size_t' mapped to CSize.

As a (dirty) workaround, one can use 'castPtr' as the marshaler when dealing
with pointers to 'size_t'. I'm a little more concerned about FunPtr's
(though 'castPtr' still makes the issue go away).

Here's my specific case dealing with function pointers:

In 64bit world, it looks like this:
type ReadableCallback = Ptr () -> Ptr CUChar -> *Ptr CULong* -> IO CUInt
{#fun gcry_ac_io_init_readable_callback {
        id `ACIO',
        id `FunPtr ReadableCallback',
        id `Ptr ()'
    } -> `()'#}

In 32bit world, it looks like this:
type ReadableCallback = Ptr () -> Ptr CUChar -> *Ptr CUInt* -> IO CUInt
{#fun gcry_ac_io_init_readable_callback {
        id `ACIO',
        id `FunPtr ReadableCallback',
        id `Ptr ()'
    } -> `()'#}

I'd really like it if I could use 'Ptr CSize' (which corresponds to the
'size_t * ptr' in the C code).

My current workaround (which doesn't use a cast in Haskell) is to redefine
the function pointer type in a C header file to use 'unsigned long' instead
of 'size_t', but this gets cludgy in a hurry. If c2hs could translate to
CSize directly, I could pass a pointer to CSize.

Is it really such a problem to make the conversion? My assumption is that
CSize would match 'size_t' for the specific architecture.

Thanks for your comment.


On Thu, Oct 1, 2009 at 12:37 PM, Duncan Coutts <duncan.coutts at googlemail.com
> wrote:

> On Thu, 2009-10-01 at 10:20 -0400, John Van Enk wrote:
> > Hello List,
> >
> > I'm running into a problem with c2hs and how it parses the C typedef
> > 'size_t'. On 32bit systems, this ends up being parsed as a CUInt. On
> > 64bit systems, this ends up as a CULong. This gets especially sticky
> > with function pointers.
> Right. Of course that's because on those different platforms size_t
> really is a typedef for unsigned int or unsigned long.
> > I see there is a ticket open for this:
> > http://hackage.haskell.org/trac/c2hs/ticket/20
> >
> > Has any one else run into this issue? Is there a good workaround that
> > doesn't involve writing a C function/typedef for each collision?
> So what you would want, presumably, is to map the "size_t" typedef to
> the Haskell type Foreign.C.Types.CSize, rather than what c2hs discovers
> as the actual raw type of "size_t". Then you're making the promise that
> unsigned long, or unsigned int really really does match
> Foreign.C.Types.CSize.
> Currently c2hs has no support for remapping basic types like that.
> As for a workaround, just use fromIntegral to convert to CSize. You know
> this is always possible because you know CSize matches CUInt or CULong
> on the appropriate platforms.
> $ cat foo.h
> #include <stddef.h>
> size_t foo(void);
> $ cat foo.c
> #include "foo.h"
> size_t foo(void) { return 42; }
> $ cat foo.chs
> import Foreign.C.Types
> foo :: IO CSize
> foo = fmap fromIntegral {# call foo as bar #}
> $ gcc -c foo.c
> $ c2hs foo.h foo.chs
> $ ghci foo.hs -fffi foo.o
> Main> foo
> 42
> Duncan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20091001/20dcb9b2/attachment.html

More information about the Haskell-Cafe mailing list