【问题标题】:Convert byte array (hex) to signed Int将字节数组(十六进制)转换为带符号的 Int
【发布时间】:2020-06-03 15:16:01
【问题描述】:

我正在尝试将(可变长度)十六进制字符串转换为有符号整数(我需要正值或负值)。

[Int16] [int 32] 和 [int64] 似乎 可以很好地处理 2,4+ 字节长度的十六进制字符串,但我被 3 字节字符串 [int24] 卡住了( powershell 中没有这样的命令)。

这是我现在拥有的(sn-p):

$start = $mftdatarnbh.Substring($DataRunStringsOffset+$LengthBytes*2+2,$StartBytes*2) -split "(..)"
[array]::reverse($start)
$start = -join $start

if($StartBytes*8 -le 16){$startd =[int16]"0x$($start)"}
elseif($StartBytes*8 -in (17..48)){$startd =[int32]"0x$($start)"}
else{$startd =[int64]"0x$($start)"}

使用上面的代码,“D35A71”的 $start 值会给出“13851249”而不是“-2925967”。我试图找出一种实现二进制补码的方法,但迷路了。有什么简单的方法可以做到这一点吗?

提前谢谢你

编辑:基本上,我想我需要实现这样的东西:
int num = (sbyte)array[0] << 16 | array[1] << 8 | array[2];
here所见。

刚刚试过这个:

$start = "D35A71"
[sbyte]"0x$($start.Substring(0,2))" -shl 16 -bor "0x$($start.Substring(2,2))" -shl 8 -bor "0x$($start.Substring(4,2))"

但似乎没有得到正确的结果:-/

【问题讨论】:

  • 你想使用 C# 吗?
  • 我不懂 C#,但试图找到一个代码来做同样的事情并转换它。那就是我迷路的地方(在翻译中)..
  • 这是干什么用的? 0xD35A71 十进制为 13851249。
  • $MFT FILE 记录 dataruns 看最高位:1101 0011 0101 1010 0111 0001 这是一个负数
  • DWORD 由 32 位而不是 24 位表示。因此,最高有效位实际上是零 (0):0000 0000 1101 0011 0101 1010 0111 0001

标签: powershell type-conversion hex powershell-4.0


【解决方案1】:

将您的十六进制数字符串解析为负数,您可以使用[bigint] (System.Numerics.BigInteger): p>

# Since the most significant hex digit has a 1 as its most significant bit
# (is >= 0x8), it is parsed as a NEGATIVE number.
# To force unconditional interpretation as a positive number, prepend '0'
# to the input hex string.
PS> [bigint]::Parse('D35A71', 'AllowHexSpecifier')
-2925967

您可以将生成的[bigint] 实例转换回[int] (System.Int32)。

注意:

  • 结果是一个负数,因为十六进制输入字符串的最高有效十六进制数字>= 0x8,即有其高位设置

    • 强制[bigint] 无条件地解释一个十六进制。输入字符串为正数前置0
  • 生成的负数数的内部two's complement表示在字节边界处执行,因此给定的十六进制数带有奇数位数(即如果第一个十六进制数字是“半字节”)缺少的半字节用1位填充。

    • 因此,最高有效数字为>= 0x8 的十六进制数字字符串(解析为负数数)导致与前面的相同数em>一个或多个 Fs (0xF == 1111) 给它;例如,以下调用 all 导致 -2048:
      [bigint]::Parse('800', 'AllowHexSpecifier'),
      [bigint]::Parse('F800', 'AllowHexSpecifier'),
      [bigint]::Parse('FF800', 'AllowHexSpecifier'), ...

有关解析逻辑的详细信息,请参阅the docs


示例:

# First digit (7) is < 8 (high bit NOT set) -> positive number
[bigint]::Parse('7FF', 'AllowHexSpecifier') # -> 2047

# First digit (8) is >= 8 (high bit IS SET) -> negative number
[bigint]::Parse('800', 'AllowHexSpecifier') # -> -2048

# Prepending additional 'F's to a number that parses as 
# a negative number yields the *same* result
[bigint]::Parse('F800', 'AllowHexSpecifier') # -> -2048
[bigint]::Parse('FF800', 'AllowHexSpecifier') # -> -2048
# ...

# Starting the hex-number string with '0' 
# *unconditionally* makes the result a *positive* number
[bigint]::Parse('0800', 'AllowHexSpecifier') # -> 2048

【讨论】:

  • 它完全符合我的要求。用$startd = [bigint]::Parse($start, 'AllowHexSpecifier') 替换了我的代码sn-p(上图)的“IF”部分,并用完整的$MFT 解析对其进行了测试。每个(负)数据运行的结果现在都是正确的。再次感谢您!
猜你喜欢
  • 2015-10-10
  • 1970-01-01
  • 1970-01-01
  • 2017-06-17
  • 2018-03-20
  • 2021-10-31
  • 2019-02-12
相关资源
最近更新 更多