Results 1 to 24 of 24

Thread: [RESOLVED] Pointer Arithmetic

  1. #1

    Thread Starter
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,480

    Resolved [RESOLVED] Pointer Arithmetic

    While we have convenient "undocumented" hidden functions like VarPtr(), StrPtr(), and ObjPtr() that return a Long... sometimes you need to add or subtract offsets.

    Since these are really ULong values, we get away with simple Long arithmetic up until the point where some of the pointers go negative. My question is:

    Has the VB6 community has ever arrived at a best practice for handling pointer offset arithmetic properly?


    "Properly" obviously means dealing with the "bit 31 on" or "negative" issue. But I'd probably go further and want it to be fast and minimal coding as well.

    I can't think of any API call that does this, but an obvious possibility involves a pair of UDTs that split up a Currency variable along with LSet statements to move data in and out. The old MS KB article How To Convert Between Signed and Unsigned Numbers suggests running the data through Double typed variables, and extrapolating from the code there a simple "PointerAdd" function could be written:

    Code:
    Function UnsignedAdd(ByVal V1 As Long, ByVal V2 As Long) As Long
        Const OFFSET_4 = 4294967296#
        Const MAXINT_4 = 2147483647
        Dim D As Double
    
        If V1 >= 0 Then D = V1 Else D = V1 + OFFSET_4
        If V2 >= 0 Then D = D + V2 Else D = D + (V2 + OFFSET_4)
        If D < 0 Or D >= OFFSET_4 Then Error 6 'Overflow.
        If D <= MAXINT_4 Then UnsignedAdd = D Else UnsignedAdd = D - OFFSET_4
    End Function
    Still, that looks awkward, and a lot more code than you'd want to use inline rather than as a function. But do we have better alternatives?

    Is there any advantage to using Currency instead of Double as the intermediate type?

  2. #2
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Pointer Arithmetic

    For small offsets, the following inline, unsigned pointer addition/subtraction works pretty well:

    Code:
    Public Const SIGN_BIT As Long = &H80000000
    
    ? "&H"; Hex$((&H7FFFFFFF Xor SIGN_BIT) + 1& Xor SIGN_BIT)
    &H80000000
    
    ? "&H"; Hex$((&H80000000 Xor SIGN_BIT) - 1& Xor SIGN_BIT)
    &H7FFFFFFF
    Unfortunately though, it fails when adding/subtracting large offsets (I haven't bothered determining exact value where it starts to fail).
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  3. #3

    Thread Starter
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,480

    Re: Pointer Arithmetic

    That looks promising, any guesses regarding what "large offsets" might be? Examples that fail?

  4. #4
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Pointer Arithmetic

    Just a dumb question? Has anyone seen a pointer that 'goes negative'? I know it is theoretically possible.

    FYI. I've cheated in the past when I felt maybe this might be an issue. The cheat involved overlaying an array (SafeArray Structure) of n-bytes over the pointer. Works well enough at a small overhead cost IMO. Likely not suitable in all scenarios.

    Edited: The assumption of course, is that VB knows how to access the data once the high bit is needed. However, you would be referencing the data at pointer xyz as array item 0 (or whatever LBound you chose).
    Last edited by LaVolpe; May 11th, 2015 at 03:42 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  5. #5
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Pointer Arithmetic

    Quote Originally Posted by dilettante View Post
    ... any guesses regarding what "large offsets" might be? Examples that fail?
    Here's a couple of extreme examples:

    Code:
    ? "&H"; Hex$((&H1 Xor SIGN_BIT) + &HFFFFFFFE Xor SIGN_BIT)          '<-- Throws RTE 6: Overflow
    'Result should've been &HFFFFFFFF
    
    ? "&H"; Hex$((&HFFFFFFFF Xor SIGN_BIT) - &HFFFFFFFE Xor SIGN_BIT)   '<-- Throws RTE 6: Overflow
    'Result should've been &H1&
    I have never encountered a need to add/subtract huge offsets from pointer values so I've never really bothered to figure out the exact range of bad values.

    Quote Originally Posted by LaVolpe View Post
    Has anyone seen a pointer that 'goes negative'? I know it is theoretically possible.
    It would be possible if the executable was marked /LARGEADDRESSAWARE and either 4-Gigabyte Tuning was enabled or the 32-bit app is running under a 64-bit Windows OS.
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  6. #6
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Pointer Arithmetic

    Quote Originally Posted by Bonnie West View Post
    It would be possible if the executable was marked /LARGEADDRESSAWARE and either 4-Gigabyte Tuning was enabled or the 32-bit app is running under a 64-bit Windows OS.
    Ah, makes sense. Thanx
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  7. #7

    Thread Starter
    PowerPoster dilettante's Avatar
    Join Date
    Feb 2006
    Posts
    24,480

    Re: Pointer Arithmetic

    Yeah, that's where I ran into it just the other day (/LARGEADDRESSAWARE).

    Thanks for the input!

  8. #8
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,414

    Re: Pointer Arithmetic

    I place Pointer-Arithmetic usually only in compiled Dlls.

    Dlls, which I always compile to Native-Code (with all extended Options checked,
    except the first one when I deal with SafeArrays in my Dlls).

    One of the checked-in Options include (besides other speed-relevant ones):
    - "No checking for Integer-Overflow"
    - ...

    and thus one is safe with directly applied Pointer-Additions, Subtractions in this case
    of native compiled Binaries.

    Here's a small snippet, so that you can try it out yourselves.

    Code:
    Option Explicit
    
    Private Sub Form_Click()
    Dim BasePtr As Long
    Cls
    
        BasePtr = &H7FFFFFFF
        Print "BasePtr", "Hex: "; Hex(BasePtr); ", Dec: "; BasePtr
        
        BasePtr = BasePtr + 1 'increment by one
        Print "Incr. by 1", "Hex: "; Hex(BasePtr); ", Dec: "; BasePtr
        
        BasePtr = BasePtr + 1 'increment by one
        Print "Incr. by 1", "Hex: "; Hex(BasePtr); ", Dec: "; BasePtr; " ... a.s.o."
        
    Print
        
        BasePtr = BasePtr - 1 'decrement by one
        Print "Decr. by 1", "Hex: "; Hex(BasePtr); ", Dec: "; BasePtr
        
        BasePtr = BasePtr - 1 'decrement by one
        Print "Decr. by 1", "Hex: "; Hex(BasePtr); ", Dec: "; BasePtr
        
        BasePtr = BasePtr - 1 'decrement by one
        Print "Decr. by 1", "Hex: "; Hex(BasePtr); ", Dec: "; BasePtr; " ... a.s.o."
    End Sub
    As said, works only natively compiled (including at least the "no check for Integer-Overflow"-Option)...

    Running the compiled executable and clicking the Form will then produce the following output:



    Olaf

  9. #9
    PowerPoster
    Join Date
    Feb 2015
    Posts
    2,766

    Re: [RESOLVED] Pointer Arithmetic

    You should use this approach: In IDE use currency for INT64 arithmetic, and in the compiled file (only Native, Ignore integer overflow check) this:
    VB Code:
    1. Option Explicit
    2.  
    3. Private Type int64cx
    4.     d As Currency
    5. End Type
    6. Private Type int64lng
    7.     l As Long
    8.     h As Long
    9. End Type
    10.  
    11. Private Sub Form_Load()
    12.     Dim inIde   As Boolean
    13.     Dim index   As Long
    14.     Dim ret     As Long
    15.    
    16.     Debug.Assert MakeTrue(inIde)
    17.    
    18.     For index = 0 To 100
    19.    
    20.         If inIde Then
    21.             Dim cx As int64cx
    22.             Dim l  As int64lng
    23.            
    24.             l.h = 0
    25.             LSet cx = l
    26.             cx.d = cx.d * 137687 + 12.3467@
    27.             LSet l = cx
    28.            
    29.             ret = l.l
    30.            
    31.         Else
    32.             ' Only this code compiled
    33.             ret = ret * 137687 + 123467
    34.            
    35.         End If
    36.        
    37.         Me.Print ret
    38.        
    39.     Next
    40.    
    41.    
    42. End Sub
    43.  
    44. Private Function MakeTrue(value As Boolean) As Boolean
    45.     MakeTrue = True
    46.     value = True
    47. End Function
    Result very fast:

  10. #10
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,523

    Re: Pointer Arithmetic

    Quote Originally Posted by dilettante View Post
    Yeah, that's where I ran into it just the other day (/LARGEADDRESSAWARE).

    Thanks for the input!
    I was bitten by this some time ago when I got Overflow errors in our log files. Had to painfully edit every place where I previously blissfully used `lPtr + 3` or `VarPtr(vArray) + 8` for instance to call `UnsignedAdd(VarPtr(vArray), 8)`

    I had a custom implementation of `UnsignedAdd` that used `Currency` or `On Error Goto ...` or both but then couple of moths ago stole Krool's implementation from this forum
    Code:
    Public Function UnsignedAdd(ByVal Start As Long, ByVal Incr As Long) As Long
        UnsignedAdd = ((Start Xor &H80000000) + Incr) Xor &H80000000
    End Function
    Works for negative `Incr` too. Obviously `Incr` cannot be above 2GB while `Start` can and is treated as unsigned ptr.

    cheers,
    </wqw>

  11. #11
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Pointer Arithmetic

    Quote Originally Posted by Bonnie West View Post
    Here's a couple of extreme examples:

    Code:
    ? "&H"; Hex$((&H1 Xor SIGN_BIT) + &HFFFFFFFE Xor SIGN_BIT)          '<-- Throws RTE 6: Overflow
    'Result should've been &HFFFFFFFF
    
    ? "&H"; Hex$((&HFFFFFFFF Xor SIGN_BIT) - &HFFFFFFFE Xor SIGN_BIT)   '<-- Throws RTE 6: Overflow
    'Result should've been &H1&
    I have never encountered a need to add/subtract huge offsets from pointer values so I've never really bothered to figure out the exact range of bad values.
    FYI. Curiosity brought this thread to mind. I think I have a safe solution that can add/subtract, using any/all of the 32 bits without the overflow errors...
    Code:
    Const SIGN_BIT = &H80000000
    
    Private Function pvSafePointerAdd(thePointer As Long, AmountToAdjust As Long) As Long
        Dim xAdj As Long
        If AmountToAdjust < 0& Then xAdj = SIGN_BIT
        pvSafePointerAdd = ((thePointer Xor SIGN_BIT) + (AmountToAdjust Xor xAdj)) Xor (SIGN_BIT Xor xAdj)
    End Function
    
    Private Function pvSafePointerSubtract(thePointer As Long, AmountToAdjust As Long) As Long
        Dim xAdj As Long
        If AmountToAdjust < 0& Then xAdj = SIGN_BIT
        pvSafePointerSubtract = ((thePointer Xor SIGN_BIT) - (AmountToAdjust Xor xAdj)) Xor (SIGN_BIT Xor xAdj)
    End Function
    Edited: of course error handling still needed should some math exceed 32 bits, i.e., value > 4,294,967,295
    Last edited by LaVolpe; Sep 14th, 2015 at 06:07 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  12. #12
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: Pointer Arithmetic

    Quote Originally Posted by LaVolpe View Post
    FYI. Curiosity brought this thread to mind. I think I have a safe solution that can add/subtract, using any/all of the 32 bits without the overflow errors...
    Code:
    Const SIGN_BIT = &H80000000
    
    Private Function pvSafePointerAdd(thePointer As Long, AmountToAdjust As Long) As Long
        Dim xAdj As Long
        If AmountToAdjust < 0& Then xAdj = SIGN_BIT
        pvSafePointerAdd = ((thePointer Xor SIGN_BIT) + (AmountToAdjust Xor xAdj)) Xor (SIGN_BIT Xor xAdj)
    End Function
    
    Private Function pvSafePointerSubtract(thePointer As Long, AmountToAdjust As Long) As Long
        Dim xAdj As Long
        If AmountToAdjust < 0& Then xAdj = SIGN_BIT
        pvSafePointerSubtract = ((thePointer Xor SIGN_BIT) - (AmountToAdjust Xor xAdj)) Xor (SIGN_BIT Xor xAdj)
    End Function
    Edited: of course error handling still needed should some math exceed 32 bits, i.e., value > 4,294,967,295
    Previously I used your code to allocate new memory,what is the difference between above code and this:
    Code:
    Private Function SafeOffset(ByVal ptr As Long, Offset As Long) As Long
    
    ' ref http://support.microsoft.com/kb/q189323/ ' unsigned math
    ' Purpose: Provide a valid/safe pointer offset. Primarily for use with CopyMemory
    
    ' If a pointer +/- the offset wraps around the high bit of a long, the
    ' pointer needs to change from positive to negative or vice versa.
    
    ' A return of zero indicates the offset exceeds the min/max unsigned long bounds
    ' Zero is an invalid memory address
    
    Const MAXINT_4NEG As Long = -2147483648#    ' min value of a Long
    Const MAXINT_4POS As Long = 2147483647      ' max value of a Long
    
        If Not ptr = 0& Then ' zero is an invalid pointer
            If Offset < 0& Then ' subtracting from pointer
                If ptr < MAXINT_4NEG - Offset Then
                    ' wraps around high bit (backwards) & changes to Positive from Negative
                    SafeOffset = MAXINT_4POS - ((MAXINT_4NEG - ptr) - Offset - 1&)
                ElseIf ptr > 0 Then ' verify pointer does not wrap around 0 bit
                    If ptr > -Offset Then SafeOffset = ptr + Offset
                Else
                    SafeOffset = ptr + Offset
                End If
            Else    ' Adding to pointer
                If ptr > MAXINT_4POS - Offset Then
                    ' wraps around high bit (forward) & changes to Negative from Positive
                    SafeOffset = MAXINT_4NEG + (Offset - (MAXINT_4POS - ptr) - 1&)
                ElseIf ptr < 0& Then ' verify pointer does not wrap around 0 bit
                    If ptr < -Offset Then SafeOffset = ptr + Offset
                Else
                    SafeOffset = ptr + Offset
                End If
            End If
        End If
    
    End Function
    Suddenly pop up in my mind: Can we use BigInteger for computing?

  13. #13
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [RESOLVED] Pointer Arithmetic

    Jonney be worth testing with the values that Bonnie posted earlier that fail using her logic (and others that use similar logic). If the code I posted years ago work, great. Then it's just a matter of CPU cycles I'd imagine. Faster/safest code should always be used for that type of function IMO, as it is likely to be used in a loop.

    Edited: One major difference is that that SafeOffset doesn't allow passing POSITIVE offsets that include the high bit, i.e., an offset of +2147483648 and greater since then the offset would be treated as a negative.
    Last edited by LaVolpe; Sep 14th, 2015 at 07:43 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  14. #14
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [RESOLVED] Pointer Arithmetic

    Quote Originally Posted by LaVolpe View Post
    Jonney be worth testing with the values that Bonnie posted earlier that fail using her logic (and others that use similar logic). If the code I posted years ago work, great. Then it's just a matter of CPU cycles I'd imagine. Faster/safest code should always be used for that type of function IMO, as it is likely to be used in a loop.

    Edited: One major difference is that that SafeOffset doesn't allow passing POSITIVE offsets that include the high bit, i.e., an offset of +2147483648 and greater since then the offset would be treated as a negative.
    I see.
    I haven't yet tested at particular situation. I set the Number of Rows to 10000000 and Cols = 5, Both code are OK without failure. In Task Management, Memory occupied only 287MB. But my ReDimPreserve2DArray failed with insufficient Memory at ReDim dummy(nNewFirstUBound, nNewLastUBound), Headache is that VB6 not allow to Redim Preserve for First Dim of 2D array:
    Code:
    Private Sub ReDimPreserve2DArray(ArrayToPreserve() As Long, nNewFirstUBound As Long, nNewLastUBound As Long)
    
    'When you use Preserve to redim an dynamic multidimensional array you can only resize the last dimension
    'and can not change the lower bounds. If you try to will generate a runtime error 9: subscript out of range.
    'For example:
    'Dim Data() As Long,ReDim Data(4,6),...,ReDim Data(24,6) will generate runtime error 9
    'But If you resize the last dimension such as ReDim Data(4,26), it is OK.
    ' http://www.vbforums.com/showthread.php?782809-ReDim-Preserve-to-a-2D-(Multi-Dimensional)-Array-in-Visual-Basic-6
    
    
        If Not ArrayIsNotEmpty(ArrayToPreserve) Then Exit Sub
    
    Dim dummy() As Long
        ReDim dummy(nNewFirstUBound, nNewLastUBound)
    
    Dim i As Long
    Dim cLen As Long
        '(That is because the the leftmost index values will be together in memory, so will be essentially a linear copy of memory located together.)
        cLen = (UBound(ArrayToPreserve, 1) + 1) * 4 
        For i = 0 To UBound(ArrayToPreserve, 2) 
            CopyMemory dummy(0, i), ArrayToPreserve(0, i), cLen 
        Next i
    
        ArrayToPreserve = dummy
    
    End Sub
    Edited: go back to my old question, what is the best work around for Redim Preserve for 2D array? If we can get rid of dummy() array, the insufficient memory may not trigger.
    Last edited by Jonney; Sep 14th, 2015 at 08:16 PM.

  15. #15
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: [RESOLVED] Pointer Arithmetic

    You can't redim the 1st dimension of a 2D array because of the way the memory is written to memory. Much like an Excel sheet. The 1st dimension are the columns and the 2nd dimension are the rows. If you have 100 rows and 20 columns, then each of the column values are written in contiguous memory for the 1st row, next 20 columns for next row and so on. Adding another column requires inserting a new memory block in front of rows 2-100 rows and one after row 100. Hope that gives a good visual.

    This is off topic and if you ant to pursue workarounds and/or different methods of storing arrayed data, might be worthy of your own thread.
    Last edited by LaVolpe; Sep 14th, 2015 at 09:23 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  16. #16
    Frenzied Member
    Join Date
    Jan 2010
    Posts
    1,103

    Re: [RESOLVED] Pointer Arithmetic

    Quote Originally Posted by LaVolpe View Post
    You can't redim the 1st dimension of a 2D array because of the way the memory is written to memory. Much like an Excel sheet. The 1st dimension are the columns and the 2nd dimension are the rows. If you have 100 rows and 20 columns, then each of the column values are written in contiguous memory for the 1st row, next 20 columns for next row and so on. Adding another column requires inserting a new memory block in front of each of the 19 rows and one after the last row. Hope that gives a good visual.

    This is off topic and if you ant to pursue workarounds and/or different methods of storing arrayed data, might be worthy of your own thread.
    OK. I opened a new thread.

  17. #17
    Default Member Bonnie West's Avatar
    Join Date
    Jun 2012
    Location
    InIDE
    Posts
    4,060

    Re: Pointer Arithmetic

    Quote Originally Posted by LaVolpe View Post
    I think I have a safe solution that can add/subtract, using any/all of the 32 bits without the overflow errors...
    Looks good! Thanks for that!
    On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
    Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)

  18. #18
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,086

    Question Re: Pointer Arithmetic

    Quote Originally Posted by Schmidt View Post
    Dlls, which I always compile to Native-Code (with all extended Options checked,
    except the first one when I deal with SafeArrays in my Dlls).
    I know this is an old thread but this is rather intriguing. Could explain how the first optimization option (Assume No Aliasing) affects SafeArray operations?

  19. #19
    PowerPoster
    Join Date
    Jun 2013
    Posts
    7,414

    Re: Pointer Arithmetic

    Quote Originally Posted by VanGoghGaming View Post
    I know this is an old thread but this is rather intriguing. Could explain how the first optimization option (Assume No Aliasing) affects SafeArray operations?
    Assume you have (in a Class) the following Helper-Vars for "array-mapping" (defined at Class-Level):
    Private WChars() As Integer, saWChars As SafeArray1D

    Then you can (in Class-Initialize) already ensure all the "Binding-necessities"
    (properly setting all the saWChars-Members and also already bind the WChars-Array).

    This will make your real routines faster, because you then only have to set:
    saWChars.pvData = StrPtr(SomeString)
    ...and your (already bound) WChars-Array will reflect the right Char-Values.

    Now, if you change the saWChars.pvData-member to different Strings(different StringPointers - e.g. when looping):
    - "Assume No Aliasing" left unchecked will always work properly
    .. (just by changing the .pvData-Member - WChars() will reflect the new String-Data)
    - "Assume No Aliasing" checked, will often not work
    .. (it often still reflects the previous Data in the WChars()-Array)

    Only observable when native compiled of course (Aliasing-optimizations are not available in IDE/PCode).

    Olaf

  20. #20
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,086

    Re: [RESOLVED] Pointer Arithmetic

    I wasn't able to reproduce this, it works as expected every time. I guess you would need some complex conditions to match in order to reproduce this issue (like passing the pvData member as a parameter to a function or something but that still works as expected so I don't know).

  21. #21
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,523

    Re: [RESOLVED] Pointer Arithmetic

    Quote Originally Posted by VanGoghGaming View Post
    I wasn't able to reproduce this, it works as expected every time. I guess you would need some complex conditions to match in order to reproduce this issue (like passing the pvData member as a parameter to a function or something but that still works as expected so I don't know).
    What did you test?

    There must be two String parameters. You must conditionally set saWChars.pvData = StrPtr(SomeString) between these two *and* modify one of the Strings, not both, so the compiler thinks second one is not touched and reuses StrPtr(SecondString) from a register or similar.

    Finally at callsite for both String actual arguments must use the same variable for aliasing to happen.

    cheers,
    </wqw>

  22. #22
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,086

    Red face Re: [RESOLVED] Pointer Arithmetic

    I think I kinda get what you're saying but I find all this aliasing concept very confusing to wrap my head around... The MSDN page about it doesn't help either, it shows a useless example where a function is called with a global parameter and then refers it using both the global name and the parameter name, nobody does that in practice...

  23. #23
    PowerPoster wqweto's Avatar
    Join Date
    May 2011
    Location
    Sofia, Bulgaria
    Posts
    5,523

    Re: [RESOLVED] Pointer Arithmetic

    Every ByRef param is susceptible to this optimization. Say you have a ByRef String and an UDT (always ByRef). When you call the procedure you can pass an instance of the UDT and again a String from this UDT i.e. Call MyProc(info.Name, info). This way you can access the same BSTR in memory using two symbols inside the procedure. This prevents the compiler from optimizing the access to actual data by each one of these symbols using a temp pointer or a CPU register unless it assumes there is no aliasing from such ByRef params. Only the developer can guarantee/fix there is no aliasing so the compiler can emit optimal codegen.

  24. #24
    PowerPoster VanGoghGaming's Avatar
    Join Date
    Jan 2020
    Location
    Eve Online - Mining, Missions & Market Trading!
    Posts
    2,086

    Re: [RESOLVED] Pointer Arithmetic

    Okay but from Olaf's reply I understood that this behavior is unpredictable, sometimes it works and other times it doesn't. I'm sure Olaf, as the developer, could have taken appropriate measures to ensure aliasing doesn't happen. So the conclusion would be that this optimization is unreliable even when we are careful about what ByRef parameters are passed to our functions.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width