newCString vs newCAString

Hi,

Module Foreign.C.String defines function newCString and newCAString with same type signature and comments, but body is different.

-- | Marshal a Haskell string into a NUL terminated C string.
--
-- * the Haskell string may /not/ contain any NUL characters
--
-- * new storage is allocated for the C string and must be
--   explicitly freed using 'Foreign.Marshal.Alloc.free' or
--   'Foreign.Marshal.Alloc.finalizerFree'.
--
newCAString :: String -> IO CString
newCAString str = do
  ptr <- mallocArray0 (length str)
  let
        go [] n     = pokeElemOff ptr n nUL
        go (c:cs) n = do pokeElemOff ptr n (castCharToCChar c); go cs (n+1)
  go str 0
  return ptr

-- | Marshal a Haskell string into a NUL terminated C string.
--
-- * the Haskell string may /not/ contain any NUL characters
--
-- * new storage is allocated for the C string and must be
--   explicitly freed using 'Foreign.Marshal.Alloc.free' or
--   'Foreign.Marshal.Alloc.finalizerFree'.
--
newCString :: String -> IO CString
newCString s = getForeignEncoding >>= flip GHC.newCString s

Per the docs of Foreign.C.String, where newCString is found under:

Using a locale-dependent encoding

These functions are different from their CAString counterparts in that they will use an encoding determined by the current locale, rather than always assuming ASCII.

This is in comparison to here, where newCAString is found under:

Using 8-bit characters

These variants of the above functions are for use with C libraries that are ignorant of Unicode. These functions should be used with care, as a loss of information can occur.

So CString is whatever your current locale specifies (usually UTF8), which requires encoding to fit into 8-bit bytes, whereas CAString is an ASCII C string, which does not.

2 Likes