B4J Question Convert 32 Bit Unsigned Hex Address strings to Long

rgarnett1955

Active Member
Licensed User
Longtime User
Hi,

I'm writing a memory analyzer for Keil uVision to display memory usage instead of having to wade through map files.

I wish to convert a string of the form: 0xhhhhhhhh to a long integer so I can do calc's. I also wish to convert the result back to hex strings.

Of course I strip off the 0x and make the remaining 8 char's upper case.

The problem I have is I don't get the answer I expect: viz

Input 0x0807dc74 = 134,732,916 decimal

But the output I get is 8,597,713,124 decimal = 0x2 0076 B0E4 in Hex

I have fiddled with the Endianess and tried bytes and strings, but with no success.

I feel it's got something to do with two's complement, but I am not sure what. It is making my brain hurt.

Can someone help me.

The code in question is:

Convert hex string to long integer:
#Region Project Attributes
    #MainFormWidth: 600
    #MainFormHeight: 600
#End Region

Sub Process_Globals
    Private fx As JFX
    Private MainForm As Form
    Private xui As XUI
    Private Button1 As B4XView
    Private Answer As Long
    Private textOPDecimal As TextArea
    Private txtInputHex As TextArea
End Sub

Sub AppStart (Form1 As Form, Args() As String)
    MainForm = Form1
    MainForm.RootPane.LoadLayout("Layout1")
    MainForm.Show
End Sub

Sub Button1_Click
    If txtInputHex.Text = "" Then
        textOPDecimal.Text = 0/0
        Return
    End If
    Answer = HexToInt(txtInputHex.Text)
    textOPDecimal.Text = Answer
End Sub

Private Sub HexToInt(hexStr As String) As Long
    Dim bc As ByteConverter
    Dim RegionUsed As Long
    Dim tempStr As String
    Dim tempByte(8) As Byte
    
    tempStr = hexStr.ToUpperCase
   
    bc.LittleEndian = False
    tempByte = bc.StringToBytes(tempStr, "UTF8")
    RegionUsed = Bit.ParseLong(bc.StringFromBytes(tempByte, "UTF8"), 32)
'    RegionUsed = Bit.ParseLong(tempStr, 32)
    Return RegionUsed
End Sub

Regards
Rob
 

emexes

Expert
Licensed User
Well, that turned out to be more complicated than expected :rolleyes: but this'll get you halfway there:

B4X:
Sub FromHexString(H As String) As Long
 
    Dim bc As ByteConverter
 
    Dim Hex16 As String = H.ToLowerCase.Replace("x", "")    'slightly dodgy way of handling "0x"

    If Hex16.Length < 16 Then
        Hex16 = "0000000000000000".SubString(Hex16.Length) & Hex16
    else If Hex16.Length > 16 Then
        Hex16 = Hex16.SubString(Hex16.Length - 16)
    End If

    Return bc.LongsFromBytes(bc.HexToBytes(Hex16))(0)

End Sub
 
Last edited:
Upvote 0

emexes

Expert
Licensed User
Well, that turned out to be more complicated than expected

If you're definitely only looking at 32-bit hex numbers (or even up to 63 bits) then this should work:

B4X:
Private Sub HexToInt(hexStr As String) As Long

    Return Bit.ParseLong(hexStr.ToLowerCase.Replace("0x", ""), 16)

End Sub

Note that ParseLong will fall over for values 0x8000000000000000 and greater ie high(sign)-bit set = negative Longs.

Your 32-bit (8-nibble) values 0xhhhhhhhh ie 0x00000000 to 0xFFFFFFFF are no problem.
 
Upvote 0

rgarnett1955

Active Member
Licensed User
Longtime User
Hi emexes,

Thanks for that. I was a knucklehead. The 16 which is the second argument of ParseLong is the radix. I thought it was the number of bits.

I knew I was doing something silly, but couldn't see the wood for the trees.

Regards
Rob
 
Upvote 0

emexes

Expert
Licensed User
Well, that turned out to be more complicated than expected :rolleyes:
You can also take Erel's Android Code Snippet [B4X] Hex Sequence to Number which is always the smartest approach to the correct answer ;)

Not quite always 🤔 :

B4X:
Sub AppStart (Args() As String)
    Dim i As Int = 0xFB461E4D
    Log(i)
    Log(StringToInt("FB461E4D"))
    'unsigned value:
    Log(StringToUnsignedInt("FB461E4D"))
    Log(StringToUnsignedInt("B461E4D"))
End Sub

Sub StringToInt(Str As String) As Int
    Dim converter As ByteConverter
    Dim ii() As Int = converter.IntsFromBytes(converter.HexToBytes(Str))
    Return ii(0)
End Sub

Sub StringToUnsignedInt (Str As String) As Long
    Dim converter As ByteConverter
    Dim a(8) As Byte
    Dim i() As Byte = converter.HexToBytes(Str)
    Bit.ArrayCopy(i, 0, a, 4, 4)
    Dim ll() As Long = converter.LongsFromBytes(a)
    Return ll(0)
End Sub

1674601913383.png
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
Not quite always 🤔 :

B4X:
Sub AppStart (Args() As String)
    Dim i As Int = 0xFB461E4D
    Log(i)
    Log(StringToInt("FB461E4D"))
    'unsigned value:
    Log(StringToUnsignedInt("FB461E4D"))
    Log(StringToUnsignedInt("B461E4D"))
End Sub
When you work with hexadecimal numbers, the convention is that you use two character positions. If you are short of a character, you must add a leading zero. The string "B461E4D" has a length of 7 so it's not meet this requirement, so the correct string is "0B461E4D".
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
After removing spaces at the beginning and end:
Test hexstring for correct length:
    Dim str As String = "B461E4D"
    Dim Length As Int = str.Length
    Dim Result As Int = Bit.And(Length,1)
    If Result = 0 Then Log("Ok") Else Log("Error")
 
Upvote 0

emexes

Expert
Licensed User
When you work with hexadecimal numbers, the convention is that you use two character positions.

When you work with hexadecimal bytes, maybe.

When you work with hexadecimal numbers, no.

Classic example being 8086 20-bit address bus = 5 hexadecimal digits.
 
Upvote 0

MicroDrie

Well-Known Member
Licensed User
What ultimately counts ;) is that the program works flawlessly 😊. When converting a number from one number system to another, as in your program with the error message, your hexadecimal string with a byte representation must be a multiple of 2 characters because a byte contains always 8 bits.
When you work with hexadecimal bytes, maybe.
A good understanding of digital arithmetic has proven invaluable for understanding and solving all kinds of network and filtering problems when communication between different sub-nets was not possible. It's now 😋 52 years after my school days when taught me how a computer does all arithmetic operations with numbers. My has been taught 8 bits is a byte. And yes, each number is divided by 2 to yield a long string of bits with ones and zeros. So not easy to read. The solution: Start by taking groups of 8-bit bit positions from right to left and displaying them as a 2-character hexadecimal number. This is the common flow that programmers follow when converting numbers and that is probably why your program gives an error, the second character is missing for the last conversion.

That calculation with bits was well stamped into my mind 52 years ago. The number 2 is binary represented by 10. With the AND function I test whether the number representation is a multiple of 2. My program example tests if any arbitrary length number is a multiple of 2 characters by testing the last bit position. In that case you can precede string and zero in the original number to avoid the error message.
 
Upvote 0

emexes

Expert
Licensed User
You can also take Erel's Android Code Snippet [B4X] Hex Sequence to Number which is always the smartest approach to the correct answer ;)
as in your program with the error message

"my" program works fine, for any length hex sequence:

Well, that turned out to be more complicated than expected :rolleyes: but this'll get you halfway there:

whereas the "correct" answer only works for half of them (ie even lengths, not odd) 🤔


and I thought it was ironic that the "always the smartest approach" would leave you at a less-robust solution ☮️
 
Upvote 0
Top