passing Strings with FFI

Manuel M. T. Chakravarty chak@cse.unsw.edu.au
Thu, 21 Jun 2001 10:59:52 +1000


"Julian Seward (Intl Vendor)" <v-julsew@microsoft.com> wrote,

> | I want to pass a String to a function which is imported from C code:
> | 	foreign import  "pass" prim_pass :: String -> String
> | The declaration above gives me an error from ghc like "String 
> | type not 
> | supported for imported functions".
> | I thought that String being [Char] should be supported 
> | (somehow like a 
> | definition with "newtype" keyword).
> | Can you tell me how can I pass strings to and from C code, as 
> | simple as 
> | possible (I know about HDirect, but I couldn't make it work 
> | for me: red-hat 
> | 7.1, ghc 5.00)?
> 
> First of all, upgrade to 5.00.2, since it is significantly less
> buggy than 5.00.
> 
> 
> int fooble ( char* str, int n )
> {
>    fprintf(stderr, "fooble called: %s %d\n", str, n );
>    return 42;
> }
> 
> 
> import PrelByteArr
> import PrelPack 	(packString)
> 
> foreign import "fooble" fooble
>    fooble :: PackedString -> Int -> IO Int
> 
> type PackedString = ByteArray Int
> 
> main = do n <- fooble (packString "hello, C world") 99
>           putStrLn ("Returned value is " ++ show n)
> 
> For more examples read the compiler sources, at 
> fptools/ghc/compiler/ghci/Linker.lhs.

Actually, the portable way of achieving the same effect with
the new FFI libraries is

  import Foreign
  import CForeign

  foreign import fooble :: CString -> Int -> IO Int

  main = withCStringLen "hello, C world" $ \(strPtr, strLen) -> do
	   n <- fooble strPtr strLen
           putStrLn ("Returned value is " ++ show n)

Note that it is not really necessary to pass the length
information explicitly.  The CString will be NUL terminated
and so directly usable by C.  I just wanted to exactly
imitate the cited example.  If you don't need the string
length, the simpler function `withCString' is sufficient.

To marshall a string from C to Haskell land, use the
function `CForeign.peekCString'.

See 

  http://haskell.cs.yale.edu/ghc/docs/latest/set/sec-foreign.html
  http://haskell.cs.yale.edu/ghc/docs/latest/set/sec-cforeign.html

for details.

The principal advantage of using Foreign and CForeign
instead of the Prel* functions is that the former are part
of the Haskell FFI standard that we are working at and so,
for example, are also supported by NHC.

Cheers,
Manuel