2011-03-01 9 views
8

मैं एक बाइनरी फ़ाइल है कि Data.Binary से जाओ इकाई का उपयोग करके हस्ताक्षरित 16bit पूर्णांकों शामिल से एक struct में पढ़ रहा हूँ बिना हास्केल में बाइनरी डेटा हस्ताक्षर हैंडलिंग। मेरे वर्तमान कोड लगता है:unsafeCoerce

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 सीधे में पढ़ने के लिए एक तरीका हो प्रतीत नहीं होता है, और न ही एक तरह से कन्वर्ट करने के लिए Word16Int16 में। क्या इसे संभालने का कोई बेहतर तरीका है?

उत्तर

8

fromIntegral int16 को Word16 परिवर्तित कर देंगे। हालांकि आपको यह जांचना होगा कि यह परिणाम प्राप्त करता है जिसके बारे में आप साइन-इन करते हैं।

+1

मुझे अच्छा लगता है: 'इंटेग्रल (अधिकतमबाउंड - 4 :: वर्ड 16) :: Int16' .. '> -5'। – sclv

+3

दस्तावेज़ कहता है: "इंटेग्रल WOrd से बाइट प्रकार को प्रतिनिधित्व द्वारा परिवर्तित करता है, मूल्य से नहीं" – fuz

3

Data.Convertible पैकेज जो आप पूछ रहे हैं उसे करना चाहिए।

उदाहरण Word16 से Int16 में कन्वर्ट करने के लिए:

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

समस्या यह है कि कि ऋणात्मक संख्याओं पर विफल रहता है > (परिवर्तित (-1 :: Word16)) :: int16 *** अपवाद: परिवर्तनीय: त्रुटि डेटा को परिवर्तित करने में त्रुटि 16535 प्रकार टाइप 16 टाइप करने के लिए int16 टाइप करें: सीमा के बाहर इनपुट मान: (-32768,32767) – user640078

1

स्टीफन के उत्तर पर बिल्डिंग एक क्रियान्वयन है जो Word8, Word16 और Word32 के लिए मौजूदा लोगों के लिए Int8, Int16 और Int32 के अनुरूप कार्यों को प्राप्त और रखता है। मैं के रूप में अभी तक Int64 या होस्ट-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]