
quoth Evan Laforge
Yes, it would be safe to say that all haskell data types which are serializable to C should have only C types. That also avoids the problem. However, you have to convert between haskell and C at some point, and that means you wind up with C and haskell duplicates of all records, so each one is actually expressed in 3 places: the C struct, the haskell "CType" record, and the haskell type record.
That could happen ... I suppose there's no one way to do it that fits every application, but often enough I can make do with the Haskell "CTYpe" record, and it gives me a Storable value that has a valid type enforced relationship to the C struct. You wouldn't always need or want a Haskell version of your C struct, per se, but if you do.
Another reason you wind up with Storable instances of non-CType records is Data.Vector.Storable. It's very tempting to simply reuse that to pass to C, and maybe it's initially fine because it has Ints or Word32s or something "safe", but then one day 2 years later someone who doesn't know about that adds a Char field and now you're in trouble.
Data.Vector.Storable is a new one on me! (I see it's in the non-portable, experimental category, so it figures.) The documentation I'm looking at seems to be saying it wouldn't be "instantiated" for Char, though?
ypoke :: Char -> Char -> Char -> IO T ypoke a b c = alloca $ \ tp -> do (#poke struct t, a) tp a (#poke struct t, b) tp b (#poke struct t, c) tp c peek tp
This is corrupting memory, since sizeOf 'c' == 4. Like I said, it will probably look like it works because it's usually just overwriting adjacent fields or perhaps alignment padding or maybe it's "safe" if it's on the stack, but you are likely to get mysterious crashes under load. Try changing the order of the pokes and see what happens.
Ah, you're right, a final poke to offset 0 overwrites everything. In retrospect I ... don't know what I was thinking! Donn