【问题标题】:Handling Signed Binary Data in Haskell without unsafeCoerce在没有 unsafeCoerce 的情况下处理 Haskell 中的签名二进制数据
【发布时间】:2015-02-21 10:31:46
【问题描述】:

我正在使用 Data.Binary 中的 Get monad 从包含有符号 16 位整数的二进制文件中读取结构。我当前的代码如下所示:

data DetectorStats = DetectorStats Int16 Word8 Word8
                     Word8 Int16 Version Int16 
                     deriving Show

getDetectorStats :: Get DetectorStats
getDetectorStats = do
  productNumber <- getWord16be
  bitPerCoordinate <- getWord8
  energyCapability <- getWord8
  timingCapability <- getWord8
  clockFrequency <- getWord16be
  serialNumber <- getWord16be
  return (DetectorStats (unsafeCoerce productNumber )
                        bitPerCoordinate
                        energyCapability 
                        timingCapability
                        (unsafeCoerce clockFrequency)
                        firmwareVersion
                        (unsafeCoerce serialNumber))

我对使用 unsafeCoerce 不满意,但似乎没有办法直接读取 Int16,也没有办法转换 Int16 strong>Word16 转换为 Int16。有没有更好的处理方法?

【问题讨论】:

    标签: haskell binary


    【解决方案1】:

    fromIntegral 会将 Word16 转换为 Int16。但是,您必须检查它是否获得了您对签名的预期结果。

    【讨论】:

    • 我觉得不错:fromIntegral (maxBound - 4 :: Word16) :: Int16..&gt; -5.
    • 文档说:“fromIntegral 将 WOrd 转换为 Byte 类型是通过表示,而不是通过值”
    【解决方案2】:

    Data.Convertible 包应该可以满足您的要求。

    例如从Word16 转换为Int16

    > (convert (6 :: Word16)) :: Int16
    6
    

    【讨论】:

    • 问题是在负数上失败 > (convert (-1 :: Word16)) :: Int16 *** 例外:可转换:将 Word16 类型的源数据 65535 转换为 Int16 类型时出错:输入值超出范围:(-32768,32767)
    【解决方案3】:

    在 Stephen 的回答的基础上,实现了 Int8、Int16 和 Int32 的 get 和 put 函数,类似于 Word8、Word16 和 Word32 的现有函数。我还没有需要 Int64 或 Host-endian 支持,但可以添加这些:

    {-# LANGUAGE RecordWildCards #-}
    module GetAndPutForInt
    ( getInt8
    , getInt16be
    , getInt16le
    , getInt32be
    , getInt32le
    , putInt8
    , putInt16be
    , putInt16le
    , putInt32be
    , putInt32le
    ) where
    
    import Data.Binary
    import Data.Binary.Get
    import Data.Binary.Put
    
    import Data.Int
    import Data.Word
    
    import qualified Data.ByteString.Lazy as B
    
    getInt8 :: Get Int8
    getInt8 = do a <- getWord8
                 return $ fromIntegral a
    getInt16be :: Get Int16
    getInt16be = do a <- getWord16be
                    return $ fromIntegral a
    getInt16le :: Get Int16
    getInt16le = do a <- getWord16le
                    return $ fromIntegral a
    getInt32be :: Get Int32
    getInt32be = do a <- getWord32be
                    return $ fromIntegral a
    getInt32le :: Get Int32
    getInt32le = do a <- getWord32le
                    return $ fromIntegral a
    
    putInt8 :: Int8 -> Put
    putInt8 i = putWord8 ((fromIntegral i) :: Word8)
    putInt16be :: Int16 -> Put
    putInt16be i = putWord16be ((fromIntegral i) :: Word16)
    putInt16le :: Int16 -> Put
    putInt16le i = putWord16le ((fromIntegral i) :: Word16)
    putInt32be :: Int32 -> Put
    putInt32be i = putWord32be ((fromIntegral i) :: Word32)
    putInt32le :: Int32 -> Put
    putInt32le i = putWord32le ((fromIntegral i) :: Word32)
    
    data TestType = TestType
        { a :: Int16
        , b :: Int16
        } deriving (Show, Eq)
    
    instance Binary TestType where
        put TestType{..} =
          do putInt16be a
             putInt16le b
        get = do a <- getInt16be
                 b <- getInt16le
                 return TestType{..}
    
    main :: IO ()
    main = do
        putStrLn "Supplies Get and Put support to Int8, Int16 etc. types as Data.Binary.Get and Data.Binary.Push do for Word8, Word 16 etc."
        putStrLn ""
        putStrLn "Test data in bytes:"
        print bytes
        putStrLn ""
        putStrLn "As TestType:"
        print (decode bytes :: TestType)
        putStrLn ""
        putStrLn "Back to bytes:"
        print $ (encode ((decode bytes) :: TestType))
      where
        bytes = B.pack $ concat $ replicate 2 [0xCD,0xEF]
    

    【讨论】:

      猜你喜欢
      • 2011-01-22
      • 1970-01-01
      • 1970-01-01
      • 2011-10-05
      • 1970-01-01
      • 1970-01-01
      • 2011-10-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多