2

I have read the contents of a binary file as an array of unsigned bytes but I want to interpret some of them as signed bytes. How do I do that?

#An array of unsigned bytes
[byte[]]$b = @(255)
#This doesn't work
[sbyte]$s = $b[0]
#Neither does this
[sbyte]$s = [convert]::ToSByte($b[0])

What I wanted was the value -1.

2
  • 1
    function AsSignedByte { param([Byte]$Byte) [sbyte]$(if($Byte -ge 128) { $Byte - 256 } else { $Byte }) } Commented Jan 3, 2018 at 23:01
  • Casting to an invalid value is, well, not valid (hence the error). The value is not in range. If you really want to do it, you can work around it as @PetSerAl notes. Commented Jan 3, 2018 at 23:03

1 Answer 1

2

The \[System.Convert\]::ToSByte(value) method raises an OverflowException if value is greater than [sbyte]::MaxValue.

Return to theory (Converting from two's complement representation):

$mask = [byte]  0x80    # [math]::pow(2,7)
$b    = [byte]  255
$s    = [sbyte] ( -($b -band $mask) + ($b -band ( -bnot $mask )) )

'result: {0,4}, {1,4} ( = 0x{0:x2}, 0x{1:x2} )' -f $b, $s

Output:

result:  255,   -1 (= 0xff, 0xff )

Of course, you could simplify the calculation as

$s    = [sbyte] ( -($b -band 0x80) + ($b -band 0x7F) )

Edit to refute PetSerAl's doubts about [sbyte] -($b -band $mask) + ($b -band ( -bnot $mask )) formula correctness. PetSerAl's doubts are right: results in Powershell-ISE differ from those in Powershell! The formula should be (see labelled parentheses)

#       ↓                                                ↓
[sbyte] ( -($b -band $mask) + ($b -band ( -bnot $mask )) )
#       ↑                                                ↑

Proof:

function AsSignedByte {     ### taken from PetSerAl's comment to the OQ
    param([Byte]$Byte) 
    [sbyte]$( if($Byte -ge 128) { $Byte - 256 } else { $Byte }) 
}

$mask = [byte]  0x80    # [math]::pow(2,7)
$good = 0
For ($i  = 0 ; $i -lt 256; $i++) {
    $b    = [byte]  $i
    $s    = [sbyte] ( -($b -band $mask) + ($b -band ( -bnot $mask )) )
    $ss   = AsSignedByte $b 
    if ( ($s -ne $ss) -or 
         ($s.GetTypeCode() -ne $ss.GetTypeCode()) -or 
         ($s -isnot [sbyte])) {
        'result: {0,4}, {1,4} ( = 0x{0:x2}, 0x{1:x2} )' -f $s, $ss
    } else { 
        $good +=1
    }
}
$good

Output:

PS D:\PShell> D:\PShell\SO\48085510.ps1
256

PS D:\PShell> 
Sign up to request clarification or add additional context in comments.

8 Comments

I think ([sbyte] -($b -band $mask)) + ($b -band ( -bnot $mask )) is not right.
@PetSerAl yes, your formula with added parentheses is not right :)
But them added according to PowerShell precedence rules to match your formula.
And what about my post edit (formula unchanged)? Maybe you think [sbyte] (-($b -band $mask) + ($b -band ( -bnot $mask )))?
Change if ( $s -ne $ss ) { to if ( ($s -isnot [sbyte]) -or ($s -ne $ss) ) {
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.