IO
C文字列にバッファを割り当てるために、少なくともある時点で関与する必要があり ます。ここでの簡単な解決策は、おそらく次のようになります。
import Foreign
import Foreign.C
import System.IO.Unsafe as Unsafe
foreign import ccall "touppers" c_touppers :: CString -> IO ()
toUppers :: String -> String
toUppers s =
Unsafe.unsafePerformIO $
withCString s $ \cs ->
c_touppers cs >> peekCString cs
Haskell 文字列をバッファにマーシャリングするために使用withCString
した場所を大文字に変更し、最後に (変更された!) バッファの内容を新しい Haskell 文字列にマーシャリング解除します。
別の解決策は、いじりをライブラリに委任することIO
ですbytestring
。パフォーマンスに興味があるなら、とにかくそれは良い考えかもしれません。ソリューションは、おおよそ次のようになります。
import Data.ByteString.Internal
foreign import ccall "touppers2"
c_touppers2 :: Int -> Ptr Word8 -> Ptr Word8 -> IO ()
toUppers2 :: ByteString -> ByteString
toUppers2 s =
unsafeCreate l $ \p2 ->
withForeignPtr fp $ \p1 ->
c_touppers2 l (p1 `plusPtr` o) p2
where (fp, o, l) = toForeignPtr s
実際にマーシャリングを行う必要はなく、ポインターを変換するだけなので、これはもう少しエレガントです。一方、C++ 側は 2 つの点で変更されています。null で終了しない可能性のある文字列を処理する必要があり (長さを渡す必要があります)、入力がコピーではないため、別のバッファーに書き込む必要があります。
参考までに、上記のインポートに適合する 2 つの簡単な C++ 関数を次に示します。
#include <ctype.h>
extern "C" void touppers(char *s) {
for (; *s; s++) *s = toupper(*s);
}
extern "C" void touppers2(int l, char *s, char *t) {
for (int i = 0; i < l; i++) t[i] = toupper(s[i]);
}