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 和 final=130976。但是,我正在检查的旧系统给出了 -96。
我有点困惑,但理论上它是十六进制表示法。我拥有的关于原始数据的唯一文档是:字符是按照 ISO Alphabet No 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
与遗留系统进行背靠背比较,这一切都匹配,但过去它并没有过多地使用十六进制,我有点谨慎。我将不胜感激有关此方法的任何进一步反馈。