2014-09-10 100 views
2

Visual Basic 2010:最近在我的一個項目中,我的任務是以十六進制讀取幾個數據字段。每個字段有三個字符。所以,這就是我一直在做:將十六進制字符串轉換爲整數

'Read the hex value and convert it to decimal 
Dim hexVal as string = "38D" 
Dim intVal as integer = Convert.ToInt32(hexVal, 16) 

'The integer result gets multiplied by a scaling factor 
'(this is set by the manufacturer for each field). 
Dim fac as single = 200 
Dim final as single = intVal * fac 
Debug.Print (final) 

這已經除非在這種情況下工作的偉大:hexVal =「FFD」和FAC = 32 .NET給我INTVAL = 4093,最終= 130976。 但是我正在檢查的遺留系統給出了-96。

我有點困惑,但推理它是在十六進制符號。我對原始數據的唯一文檔狀態是:字符按ISO字母5編碼,每個字符使用7位,即不添加奇偶校驗位。三個這樣的字符將包含每個32位字的字段。

我是否將此錯誤地轉換?

附錄:我研究了這些字段的定義,並發現幾乎所有的字符都是正的(或無符號的)。一些可以是負面的或正面的(簽名)。查看遺留代碼,對於每個十六進制字段,它們計算無符號結果和簽名結果。如果該字段預計總是正值,那麼他們使用無符號結果。現在,如果字段預期爲負值或正值,則它們取無符號結果,如果高於最大值,則使用簽名結果,否則使用無符號結果。以下是我迄今爲止從下面的代碼片段:

Dim hexVal As String, res As Single, decCeiling As Single 
    Dim paddedHex1 As String, intVal1 As Integer = 0, resVal1 As Single = 0 
    Dim paddedHex2 As String, intVal2 As Integer = 0, resVal2 As Single = 0 
    Dim IsUnsignedInput As Boolean 

    hexVal = "FB1" 'Raw hex input (in this case represents temperature in deg C) 
    res = 0.125  'A resolution factor. Used to scale the decimal to a real-world nummber 
    decCeiling = 150 'The maximum temperature we can expect is 150 degree Celcius 
    IsUnsignedInput = False 'Is field unsigned or signed (for temps we can expect negative and positive) 
    If hexVal.Length > 8 Then 
     Throw New Exception("Input '" & hexVal & "' exceeds the max length of a raw input. The max is 8 characters.") 
    EndIf 

    'This calcualtion assumes an unsigned value (that is, always a positive number) 
    paddedHex1 = hexVal.ToString.PadLeft(8, CChar("0")) 
    intVal1 = Convert.ToInt32(paddedHex1, 16) 
    resVal1 = intVal1 * res 

    'This assumes a signed value (that is, could be a negative OR positive number. 
    'Use two's complement to arrive at the result. 
    paddedHex2 = hexVal.PadLeft(8, CChar("F")) 
    Dim sb As New StringBuilder(paddedHex2.Length) 
    For i As Integer = 0 To paddedHex2.Length - 1 
     Dim hexDigit As Integer = Convert.ToInt32(paddedHex2(i), 16) 
     sb.Append((15 - hexDigit).ToString("X")) 
    Next i 

    Dim inverted As Integer = Convert.ToInt32(sb.ToString, 16) 
    intVal2 = -(inverted + 1) 
    resVal2 = intVal2 * res 

    'Finally, which result do we use as the final decimal? For our example we get 
    'resVal1 (unsigned)=+502.125 
    'resVal2 (signed) = -9.875 
    'Field is signed so is 502.125 > 150? Yes, so use the signed result of -9.875. 
    If IsUnsignedInput Then 
     'If unsigned then we always expect a positive value so use straight conversion. 
     Debug.Print("Result=" & resVal1) 
    Else 
     'If signed then we expect a positive OR negative value 
     If resVal1 > decCeiling Then 
      'Standard conversion yields a higher number than expected so use two's complement to get number 
      Debug.Print("Result=" & resVal2) 
     Else 
      'Standard conversion yields a number that is in the expected range so use straight conversion to get number 
      Debug.Print("Result=" & resVal1) 
     End If 
    End If 

做與傳統系統的所有匹配起來背到後端的比較,但它不與十六進制過去太多的工作,我有點謹慎。我希望對此方法提供進一步的反饋意見。

回答

4

intVal = 4093是正確的。
final = 130976也是正確的。

FFD也可以解釋爲-3表示在二進制補碼(這是計算機如何存儲負值)。 32 * -3 = -96。

FFD    = 111111111101 (binary) 

在補,當第一位是1,這意味着該數字爲負數。爲了否定的數目,第一反轉所有的位,然後添加1:

FFD inverted =  000000000010 
+ 1   =  000000000011 = 3 (decimal). 

由於3是取反數,實數必須是-3。

你也可以用十六進制表示法來做到這一點。如果第一個十六進制數字> = 8,則表示負數。因此,通過執行以下操作更換否定號:

0 -> F 
1 -> E 
2 -> D 
3 -> C 
4 -> B 
5 -> A 
6 -> 9 
7 -> 8 
8 -> 7 
9 -> 6 
A -> 5 
B -> 4 
C -> 3 
D -> 2 
E -> 1 
F -> 0 

(第二列簡單的羅列相反的順序,16進制數。)

所以對於FFD你得到002(十六進制)。您可以將此十六進制數轉換爲十進制數,並加1,得到3.因爲這表示負值,請將其乘以-1。 3 * -1 = -3。

Function ConvertHex(ByVal hexVal As String) As Integer 
    If hexVal(0) >= "8"c Then 'We have a negative value in the 2's complement 
     Dim sb As New System.Text.StringBuilder(hexVal.Length) 
     For i As Integer = 0 To hexVal.Length - 1 
      'Convert one hex digit into an Integer 
      Dim hexDigit As Integer = Convert.ToInt32(hexVal(i), 16) 

      'Invert and append it as hex digit 
      sb.Append((15 - hexDigit).ToString("X")) 
     Next i 

     'Get the inverted hex number as Integer again 
     Dim inverted As Integer = Convert.ToInt32(sb.ToString(), 16) 

     'Add 1 to the inverted number in order to get the 2's complement 
     Return -(inverted + 1) 
    Else 
     Return Convert.ToInt32(hexVal, 16) 
    End If 
End Function 

但是,如果你總是有3個十六進制數字,你可以簡單地做這

Function ConvertHex3(ByVal hexVal As String) As Integer 
    Dim number = Convert.ToInt32(hexVal, 16) 
    If hexVal(0) >= "8"c Then 
     Return number - &H1000 
    Else 
     Return number 
    End If 
End Function 

這是聰明的多!

+0

因此,如果我的目標是創建一個.NET應用程序來完成遺留系統的功能,那麼您會在這裏建議什麼路徑?我應該轉向不同類型的轉換方法嗎? – sinDizzy 2014-09-10 21:07:07

+0

謝謝!老實說,你的第二次編輯我有你的最後一個例程的一半。 Dim c As Char = CChar(hexVal.Substring(0))then dim highBits()As Char = {「8」c,「9」c,「A」c,「B」c,「C」c,「D 「c」,「E」c,「F」c}然後Dim IsNeg As Boolean = highBits.Contains(c)。但你的簡潔得多。 – sinDizzy 2014-09-10 21:54:56

+0

好吧,我正在從我們的遺留系統程序員獲取信息的位。他通常說,可能有負值的字段長度爲4或8個十六進制字符。如果我從命令行轉換使用遺留系統,我得到這個:TOHEX -3 = FFFFFFFD,也是TOHEX 2068 = 00000814.我認爲它的內部例程需要8個字符,例如TODEC FFD = 4093和TODEC 814 = 2068。我得到的例程高於0x814 = -2028。我只是沒有得到我們遺留系統正在做的調整。它是否調整了8個字符?我應該留下填充我的十六進制值來獲得4或8個字符? – sinDizzy 2014-09-10 22:28:30

相關問題