I try to call a C function with the declaration from Haskell side:
int IupOpen(int *argc, char ***argv);
Then I do the following binding:
foreign import capi "iup.h IupOpen"
c_IupOpen :: Ptr CInt -> Ptr (Ptr CString) -> IO CInt
iupOpen :: Maybe [String] -- ^ Program's command line arguments
-> IO Int -- ^ The initialization status flag
iupOpen args = case args of
Nothing -> fromIntegral <$> c_IupOpen nullPtr nullPtr
Just argv -> alloca $ \argcPtr -> do
poke argcPtr (fromIntegral . length $ argv)
argvs <- mapM (`withCString` return) argv
pCstr <- withArray argvs return
argvPtr <- alloca $ \ppCstr -> poke ppCstr pCstr >> return ppCstr
fromIntegral <$> c_IupOpen argcPtr argvPtr
After compiling, the following warning is given:
C:\...\AppData\Local\Temp\ghc6096_0\ghc_5.c: In function 'ghczuwrapperZC1ZChiupzm0zi1zi0zi0zm1ddNNYbMeka1JTSCkHxKK2ZCGraphicsziIUPziRawziIupZCIupOpen':
C:\...\AppData\Local\Temp\ghc6096_0\ghc_5.c:10:143: warning: passing argument 2 of 'IupOpen' from incompatible pointer type [-Wincompatible-pointer-types]
10 | HsInt32 ghczuwrapperZC1ZChiupzm0zi1zi0zi0zm1ddNNYbMeka1JTSCkHxKK2ZCGraphicsziIUPziRawziIupZCIupOpen(void* a1, void*** a2) {return IupOpen(a1, a2);}
| ^~
| |
| void ***
In file included from C:\...\AppData\Local\Temp\ghc6096_0\ghc_5.c:7:
C:/.../hs/hs-iup/iup-3.30_Win64_mingw6_lib/include/iup.h:37:56: note: expected 'char ***' but argument is of type 'void ***'
37 | IUP_API int IupOpen (int *argc, char ***argv);
But the parameter argvPtr I passed is really of type Ptr (Ptr CString). I don't understand why this warning happens.
Thans for any ideas!
=======Update 1===========
After some tries, I solved the issue by replacing capi with ccall. It seems that capi have a procedure to produce some wrapper functions, which don't have the proper type signature.
But still I don't know why capi can't work correctly? Is it a bug or due to anything that I haven't noticed?
======Update 2=============
New code without dangling pointers (I believe ^_^):
foreign import capi "iup.h IupOpen"
c_IupOpen :: Ptr CInt -> Ptr (Ptr CString) -> IO CInt
open :: Maybe [String] -- ^ Program's command line arguments
-> IO Int -- ^ The initialization status flag
open args = case args of
Nothing -> fromIntegral <$> c_IupOpen nullPtr nullPtr
Just argv -> alloca $ \ptrArgc -> do
poke ptrArgc (fromIntegral . length $ argv)
alloca $ \ptrCStr -> do
cstrArr <- mapM newCString argv -- to free an array of pointer
pokeArray ptrCStr cstrArr
alloca $ \pptrCStr -> do
poke pptrCStr ptrCStr
flag <- c_IupOpen ptrArgc pptrCStr
mapM_ free cstrArr
return . fromIntegral $ flag
The pointer type is still mismatched unless using ccall.
=============Update 3=====================
Well, finally I find that it's a bug according to the issue #15531