MemoryBlock and pointers

I would like to store data in a MemoryBlock aligned to 4 bytes, like that:

Dim mb As New MemoryBlock(10 * 4)
mb.Int32Value(0) = aIntegerValue
mb.Int8Value(4) = CType(aByteValue, Integer)
mb.SingleValue(8) = aSingleValue
// and so on for values which take 4 or less bytes

This works fine. And for values using more than 4 bytes (Int64s, Doubles, Strings) I would like to store a pointer to the value

mb.Ptr(12) = aPointerToADouble
mb.Ptr(16) = aPointerToAString

How can I get a pointer to a Double or String. Of course I tried to store the values in a separate MemoryBlock each:

Dim aPointerToADouble As New MemoryBlock(8)
aPointerToADouble.DoubleValue(0) = aDoubleValue
mb.Ptr(12) = aPointerToADouble

and

Dim aPointerToAString As MemoryBlock = aStringValue
mb.Ptr(16) = aPointerToAString

But this does not work. What am I doing wrong here?

trying to get a ptr to something that you really cant get a ptr to :stuck_out_tongue:

This line doesn’t make sense to me:

mb.Int8Value(4) = CType(aByteValue, Integer)

So you are trying to store a single byte at the 5th position of the MemoryBlock, but you are converting it to an Integer (currently 4 bytes) first?

It appears that you can convert a Pointer to a UInt32 value, then stuff that value in the destination memory block, as follows:

  dim mb as MemoryBlock = "Testing"
  dim mb2 as new MemoryBlock(4)
  
  dim p as Ptr = mb
  dim i as Uint32 = Uint32(p)
  dim h as string = hex(i)  // check this value in the debugger for fun and profit!
  mb2.UInt32Value(0) = i

In the debugger you can clearly see that the value of i (when converted to Hex) is the same as p

1 Like

Michael, you can do this directly with MemoryBlock.Ptr. You don’t need to go through an UInt32.

I just tested this code and it works just fine:

  dim mb as new MemoryBlock( 40 )
  dim stringMB as new MemoryBlock( 20 ) 
  stringMB.CString( 0 ) = "some string" + ChrB( 0 )
  
  dim p as Ptr = stringMB
  mb.Ptr( 0 ) = p
  
  dim doubleMB as new MemoryBlock( 8 )
  doubleMB.DoubleValue( 0 ) = 3.123
  p = doubleMB
  mb.Ptr( 4 ) = p
  
  p = mb.Ptr( 0 )
  dim newMB as MemoryBlock = p
  dim s as string = newMB.CString( 0 )
  
  newMB = mb.Ptr( 4 )
  dim d as double = newMB.DoubleValue( 0 )

Kem, the LR says “MemoryBlock.Ptr: Returns a MemoryBlock with an unknown size. It sets Size to -1 but it still can be used to access its data. Offset is in bytes from the beginning of the MemoryBlock.” It says nothing about using Ptr(offset) as a Setter.

So either you are just creating a new memory block (in which case that code probably doesn’t work), or perhaps the LR is incorrect?

The LR is incomplete in that case. Just for completeness, the old way to accomplish this was

dim mb1, mb2 as MemoryBlock
mb1 = …
mb2 = …
mb1.IntegerValue(x) = AddressOf mb2

Ptr() is clearer/easier.

I’ll take a look at updating the LR, but my code does work. I tested before I posted it.

Btw, because the MemoryBlock is of Size -1, I had to use a CString for the string.

Kem Tekinay: Thanks Kem, works well. My mistake was that I didn’t realize that MemoryBlocks get released as any other variable when they go out of scope from where they were declared. So I just add these MemoryBlocks for values which need 8 or more bytes to an array, and now I can use them everywhere in my class.

Just FYI, it does now. :slight_smile:

Thanks Kem - so can you clarify what this means?

It sounds like MemoryBlock.Ptr(offset) has two very different meanings:

  • mode 1 : returns a new memory block
  • mode 2 : functions just like the Setters for the other functions (.byte .Uint32 etc.)

Amirite?

(edit: or am i wrong: does the Getter version of Ptr() return a new memory block?)

I think there might be some fundamental confusion, so I’ll start at the top.

A Ptr is a representation of an address in memory. Every item that is stored has such an address, but in Xojo, you can get the address for such things as a MemoryBlock or method.

A MemoryBlock is reserved spot in memory of a given size into which you can store and retrieve bytes. A new MemoryBlock starts initialized at all zeros.

When you store MemoryBlock.Ptr, you are storing the address (currently 4 bytes) of the item. When you retrieve that Ptr, you are retrieving that address.

When you retrieve the address as a MemoryBlock, there is no way for the system to know how big the MemoryBlock is, so its size is set to -1, effectively “infinite”, so it’s up to you to know how much of the memory you are actually using.

If you create a new MemoryBlock(4) and immediately retrieve p = mb.Ptr(0), you will end up with an infinite MemoryBlock starting at address &h0000, which is effectively useless and potentially dangerous.

Looking at it another way, when you retrieve a MemoryBlock.Ptr, you are saying, “show me the bytes that start at that address.” If the address is random, the results will be meaningless, but it won’t be a “new” MemoryBlock.

Did I answer your question?

No, but that’s OK, I think we are talking across each other.

The issue I’m having is that the old LR was incorrect : it said that MemoryBlock.Ptr(offset) would create a new memoryblock at the offset. That wasn’t true : what actually happens is that MemoryBlock.Ptr(offset) would use the 4 bytes stored at MemoryBlock(offset…offset + 3), convert that to a pointer, which is entirely not the same thing. (In C terms, it’s the difference between &ptr and *ptr ). You edited the LR now so that’s OK.

Of interest, if you do the test you proposed:

  dim mb1 as new MemoryBlock(4)
  dim p1 as Ptr = mb1.Ptr(0)

A nilObjectException is triggered, which is interesting - a little unexpected but not insane.

Here’s how I would clarify things in the LR, by adding this sentence:

Note the difference in function between setting a Ptr to equal a MemoryBlock vs. using the MemoryBlock.Ptr(offset) function: In the first case, the Pointer will point to the MemoryBlock itself; in the latter case, the Pointer will be set to the value of the 4 bytes stored inside the memoryBLock from offset to offset+3. The pointer will not point to the address of those bytes.

When you say, “the test you proposed,” where did you see that code? I don’t recall writing that, and it’s not in the LR, at least not like that. I wouldn’t want someone to do that, so I’d like to clean it up.

As for your proposed addition, point taken. I’m writing a bit a differently, but you’ll be able to see the change soon. Feel free to comment.

In the prior post where you said “If you create a new MemoryBlock(4) and immediately retrieve p = mb.Ptr(0)”
Late night? Your caffeine to blood ratio too low? :slight_smile:

No, what you “quoted” and what I wrote were different enough that I didn’t make the connection, but that’s fine. I just wanted to make sure I didn’t inadvertently include something like that in the LR. It’s all good.