Converting A UInt32 To Bytes

Hi all,

What’s the best way to convert a 32-bit unsigned integer (UInt32) to an array of Bytes? I’m writing a bytecode interpreter and I need to store a 32-bit integer as four 8-bit operands (little endian).

Any idea how to do this? I want this to run on iOS so it if involves a MemoryBlock it’ll have to be Xojo.Core.MemoryBlock, not the classic MemoryBlock. I say this because it looks like you used to be able to get/set UInt32 values with the class MemoryBlock but only get UInt32 values from both Xojo.Core.MemoryBlock and Xojo.Core.MutableMemoryBlock.

Any help would be greatly appreciated.

Thanks,

you can use AND with the right mask & shifts

ie/
&h12345678 and &hff000000 shifted right 24 spots => &h12
&h12345678 and &h00ff0000 shifted right 16 spots => &h34
&h12345678 and &h0000ff00 shifted right 8 spots => 56
&h12345678 and &h000000ff => 78

Something like this should be quickest:

dim arr() as Byte
arr.Append v and &hFF
arr. Append ( v and &hFF00 ) \\ CType( 256 ^ 1, UInt32 )
arr.Append ( v and &hFF0000 ) \\ CType( 256 ^ 2, UInt32 )
arr.Append ( v and &hFF000000 ) \\ CType( 256 ^ 3, UInt32 )

(Untested.)

Shift is a lot faster than division.
Unless llvm optimizes the diff to a shift…

It seems to, and ShiftRight/Left are actually function calls so they are slower because of the overhead.

This could be enough to many cases.

[code] Dim m As New MutableMemoryBlock(4)

Dim i As Uint32 = &h12345678

// Sets Uint32

m.UInt32Value(0)=i

// Read bytes

Dim b As Byte

b=m.UInt8Value(0) // &h78
b=m.UInt8Value(1) // &h56
b=m.UInt8Value(2) // &h34
b=m.UInt8Value(3) // &h12

// Set bytes

m.UInt8Value(0) = 4
m.UInt8Value(1) = 3
m.UInt8Value(2) = 2
m.UInt8Value(3) = 1

// Gets Uint32

i = m.UInt32Value(0)
[/code]

Thanks for the responses guys. I’ve done some testing and I think there must be some LLVM optimisation going on as there is virtually no difference in execution speed between Kem’s division approach and Norm’s BitWise.ShiftRight approach. Below are two methods which do the same thing (take an Integer and return an array of four bytes). Obviously this won’t work correctly if the integer value is > 4,294,967,295 (UInt32 limit):

[code]Public Function IntegerToBytes(i As Integer) as Byte()
// Takes an integer (<4,294,967,295) and returns it as an array of bytes
// (little endian) with element(0) being the least signifiant byte.
Dim b0 As Byte = (i And &h000000FF)
Dim b1 As Byte = (i And &h0000FF00) \ CType(256 ^ 1, UInt32)
Dim b2 As Byte = (i And &h00FF0000) \ CType(256 ^ 2, UInt32)
Dim b3 As Byte = (i And &hFF000000) \ CType(256 ^ 3, UInt32)

Return Array(b0, b1, b2, b3)

End Function[/code]

[code]Public Function IntegerToBytesShift(i As Integer) as Byte()
// Same as above but using the Bitwise module instead of division.
Dim b0 As Byte = i And &h000000FF
Dim b1 As Byte = Bitwise.ShiftRight(i And &h0000FF00, 8, 32)
Dim b2 As Byte = Bitwise.ShiftRight(i And &h00FF0000, 16, 32)
Dim b3 As Byte = Bitwise.ShiftRight(i And &hFF000000, 24, 32)

Return Array(b0, b1, b2, b3)

End Function[/code]

Testing:

[code]Dim i As Integer = &h12345678
Dim bytes1(), bytes2() As Byte

Dim start As Double = Microseconds
For a As Integer = 0 To 50000
Redim bytes1(-1)
bytes1 = IntegerToBytes(i)
Next a
Dim end1 As Double = (Microseconds - start)/1000

start = Microseconds
For a As Integer = 0 To 50000
Redim bytes2(-1)
bytes2 = IntegerToBytesShift(i)
Next a
Dim end2 As Double = (Microseconds - start)/1000[/code]

The above test code (50,000 iterations of each) yields:

  • Division: 39.4 microseconds
  • Bitwise: 41.3 microseconds

Whilst the difference is negligible, I think I’ll use Kem’s approach (IntegerToBytes() method) as the Bitwise module is not available on iOS.