Library tutorials & articles

CopyMemory and Arrays: Proper Use

The Tricky Part

I mentioned that the calculation of the number of bytes to be moved was tricky. Well, it is because Visual Basic will pad certain UDT's with non-used bytes. But what does this mean? I'll detail this with an example.

Look at the following UDT:

Private Type TestType
    var1 As Long
    var2 As Integer
    var3 As Single
End Type

TestType seems to occupy 10 bytes: 4 bytes for the long (var1), 2 bytes for the integer (var2), and 4 bytes for the single number (var3). However, if you run the following code snippet you will prove this is not correct.

Public Sub Main()

Dim myVar As TestType

    MsgBox "LenB(myVar) = " & CStr(LenB(myVar)), vbInformation
End Sub

The message box will read "LenB(myVar) = 12". This can only mean one thing: Visual Basic will align the second variable in memory so it occupies 4 bytes instead of 2. This is normally referred to as DWORD alignment.

NOTE: DWORD stands for "double word", and it is a term that comes from the old computing days. A Word is two bytes, a DWORD is four bytes, and now with the introduction of 64-bit machines, a QWORD (quad word) is 8 bytes. Windows programming in C++ have maintained this nomenclature.

If you like, you can mess with the order of the variables in TestType. If you do, you will notice that if the integer goes down to the last position like in the following UDT, LenB() will return the original expected result: 10. A new piece of information for the resolution of this puzzle: A 2-byte variable will not be DWORD-aligned if it is at the end of the UDT.

Private Type TestType
    var1 As Long
    var3 As Single
    var2 As Integer
End Type

Now let's try with one-byte variables. Run the previous test with this UDT declaration:

Private Type TestType
    var1 As Long
    var2 As Byte
    var3 As Single
End Type

The result is 12 bytes again. But what about this next one?

Private Type TestType
    var1 As Long
    var3 As Single
    var2 As Byte
End Type

The result is 9 bytes, the result we could have obtained by manually adding up the bytes for each data type. Now the puzzle is almost complete. Let us see what happens with a more complex UDT:

Private Type TestType
    var1 As Long
    var2 As Byte
    var4 As Byte
    var3 As Single
End Type

This one returns 12 too. The following also yields 12.

Private Type TestType
    var1 As Long
    var2 As Integer
    var4 As Integer
    var3 As Single
End Type

Summarizing...

What can we say about these tests? Well, we can say that all variables not occupying a multiple of 4 bytes in the middle of a UDT declaration (the order of declaration determines the order they are stored in memory) will get padded so they are DWORD-aligned.

And to wrap this result up with CopyMemory, I must say that the number of bytes is of PARAMOUNT importance because you will not get the correct results if you do not use the correct number of bytes. This could happen if you confuse LenB() with Len(), or if you hardcode the number of bytes occupied by a UDT.

To finally complete the discussion on CopyMemory and UDTs and arrays, I must note a few restrictions of use. Please read the next page of this article.

Comments

  1. 26 Jun 2004 at 07:49

    Thanks. Definately some good information, however...


    It is not very practical to use the ReDim statement each iteration of a loop since it copies the entire array to a different memory location in order to change the dimension. In fact, using the CopyMemory function for this purpose is useful as well. A good compromise would be to redimension the array every 20th iteration and then check for empty array values, such as:


    If SubDirCount = UBound(DirList) Then ReDim Preserve DirList(UBound(DirList) + 20)


    an even better solution is to use an array object.

  2. 01 Mar 2003 at 13:25

    I just tested and yes, you are correct.


    Private Type MyType
       var1 As Integer
       var2 As Byte
       var3 As Boolean
    End Type


    The above type will get padded to a WORD, not a DWORD.  However, starting with a WORD is not enough.  The following will get DWORD-aligned, meaning you must not have DWORDS or QWORDS.


    Private Type MyType
       var1 As Integer
       var2 As Byte
       var3 As Long
    End Type


    Private Type MyType
       var1 As Integer
       var2 As Byte
       var3 As Double
    End Type


    Private Type MyType
       var1 As Integer
       var3 As Double
    End Type


    Thanks for the observation.  I will update the article to add the finding.

  3. 01 Mar 2003 at 11:03

    I'm willing to bet that if he first variable in the UDT had been an integer, the following Bytes would have been padded to WORD size and no more.


    This being the start of the week-end, I'll play with this later...

  4. 01 Jan 1999 at 00:00

    This thread is for discussions of CopyMemory and Arrays: Proper Use.

Leave a comment

Sign in or Join us (it's free).

Jose Pablo Ramirez Vargas

Related discussion

Related podcasts

  • Christian Beauclair

    14 mai 2008 (�mission #0074) ::.Christian Beauclair: Stratégies de migration VB6 vers .NET Nous discutons avec Christian Beauclair des stratégies de migration VB6 vers .NET. Entre autres, nous discutons comment utiliser le "VB 6 Code Advisor" et le "Interop Forms Toolkit" pour ajouter la puiss...

Want to stay in touch with what's going on? Follow us on twitter!