|
-
Feb 18th, 2019, 04:15 PM
#1
Thread Starter
Fanatic Member
[RESOLVED] CopyMemory a range of integer array values to create a string?
I have an integer array containing character codes. I want to create a string from a range of these character codes. I know that I can do this by concatenating the Chr$() of each character code, But I'm wondering if this can be done faster and in one go using CopyMemory. Everything I try either crashes or doesn't work.
Ex.
Dim arrCharCodes(1 to 5) as Integer
arrCharCodes(1) = 65 'A
arrCharCodes(2) = 66 'B
arrCharCodes(3) = 67 'C
arrCharCodes(4) = 68 'D
arrCharCodes(5) = 69 'E
dim strCharCodes as String
strCharCodes = Chr$(arrCharCodes(2)) & Chr$(arrCharCodes(3)) & Chr$(arrCharCodes(4))
'results in strCharCodes = "BCD"
Can this be achieved faster using CopyMemory to copy a range of values from the Integer array into a string variable? If so, how?
-
Feb 18th, 2019, 04:35 PM
#2
Re: CopyMemory a range of integer array values to create a string?
Code:
Public Function WCHARtoStr(aCh() As Integer) As String
Dim sBuf As String
sBuf = String$(UBound(aCh) + 1, 0)
CopyMemory ByVal StrPtr(sBuf), aCh(0), LenB(sBuf)
WCHARtoStr = sBuf
End Function
or if you want to have that procedure itself able to select a range:
Code:
Public Function WCHARtoStrEx(aCh() As Integer, Optional ByVal nStart As Long = 0&, Optional ByVal nEnd As Long = -1&) As String
Dim sBuf As String
Dim nCh As Long
If nEnd = -1& Then nEnd = UBound(aCh)
nCh = (nEnd - nStart) + 1
sBuf = String$(nCh, 0)
CopyMemory ByVal StrPtr(sBuf), aCh(nStart), nCh * 2
WCHARtoStrEx = sBuf
End Function
nStart and nEnd refer to the integer array so are zero-based. For ABCDE 1,3 would return BCD.
Last edited by fafalone; Feb 18th, 2019 at 04:50 PM.
-
Feb 18th, 2019, 05:53 PM
#3
Re: CopyMemory a range of integer array values to create a string?
I'd tend to be a bit careful about the LBound of the incoming array. Something like the following to initialize the string might be a bit better:
Code:
sBuf = String$(UBound(aCh) - LBound(aCh) + 1, 0)
And then maybe the following for the CopyMemory:
Code:
CopyMemory ByVal StrPtr(sBuf), aCh(LBound(aCh)), LenB(sBuf)
This would do better at accommodating AAraya's array:
Code:
Dim arrCharCodes(1 to 5) as Integer
Any software I post in these forums written by me is provided "AS IS" without warranty of any kind, expressed or implied, and permission is hereby granted, free of charge and without restriction, to any person obtaining a copy. To all, peace and happiness.
-
Feb 18th, 2019, 10:18 PM
#4
Re: CopyMemory a range of integer array values to create a string?
 Originally Posted by AAraya
Can this be achieved faster using CopyMemory ...
Why bother with CopyMemory when there are API functions that deals specifically with BSTRs?
Code:
Option Explicit
Private Declare Function SysReAllocStringLen Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long, Optional ByVal Length As Long) As Long
Private Sub Main()
Dim arrCharCodes(1 To 5) As Integer
Dim strCharCodes As String
arrCharCodes(1) = 65 'A
arrCharCodes(2) = 66 'B
arrCharCodes(3) = 67 'C
arrCharCodes(4) = 68 'D
arrCharCodes(5) = 69 'E
If SysReAllocStringLen(VarPtr(strCharCodes), VarPtr(arrCharCodes(2&)), 3&) Then
MsgBox """" & strCharCodes & """", vbInformation
End If
End Sub
-
Feb 19th, 2019, 11:35 AM
#5
Thread Starter
Fanatic Member
Re: CopyMemory a range of integer array values to create a string?
 Originally Posted by fafalone
Code:
Public Function WCHARtoStr(aCh() As Integer) As String
Dim sBuf As String
sBuf = String$(UBound(aCh) + 1, 0)
CopyMemory ByVal StrPtr(sBuf), aCh(0), LenB(sBuf)
WCHARtoStr = sBuf
End Function
Thanks! I was right there myself but wasn't creating a buffer. I was trying to copy to the sBuf string variable without creating a buffer. DOH!
-
Feb 19th, 2019, 11:37 AM
#6
Thread Starter
Fanatic Member
Re: CopyMemory a range of integer array values to create a string?
 Originally Posted by Victor Bravo VI
Thanks for sharing those functions! I hadn't used those before. Performance-wise your method is very close to the CopyMemory method so I'm not sure what advantage there is to using one over the other.
-
Feb 19th, 2019, 12:31 PM
#7
Re: [RESOLVED] CopyMemory a range of integer array values to create a string?
Code:
Dim CharCodes() As Byte
Dim Chars As String
ReDim CharCodes(1 To 10)
CharCodes(1) = 65 'A
CharCodes(3) = 66 'B
CharCodes(5) = 67 'C
CharCodes(7) = 68 'D
CharCodes(9) = 69 'E
Chars = CharCodes
MsgBox Chars
-
Feb 19th, 2019, 02:31 PM
#8
Thread Starter
Fanatic Member
Re: [RESOLVED] CopyMemory a range of integer array values to create a string?
 Originally Posted by dilettante
Code:
Dim CharCodes() As Byte
Dim Chars As String
ReDim CharCodes(1 To 10)
CharCodes(1) = 65 'A
CharCodes(3) = 66 'B
CharCodes(5) = 67 'C
CharCodes(7) = 68 'D
CharCodes(9) = 69 'E
Chars = CharCodes
MsgBox Chars
Thanks dilettante.
I'm aware of assigning a byte array directly to a string. 1) I don't have a byte array, I have an array of integers. And they're not in Unicode format (with every other byte being a zero). This method won't work for me, will it? 2) I don't want to assign the entire integer array to a string but just a portion of it. How does that work with your method?
-
Feb 19th, 2019, 02:50 PM
#9
Re: CopyMemory a range of integer array values to create a string?
 Originally Posted by AAraya
Performance-wise your method is very close to the CopyMemory method so I'm not sure what advantage there is to using one over the other.
Well, SysReAllocStringLen combines String$ + CopyMemory in one function call.
OK, so I did some benchmarks and here are the results on my machine (all times are in seconds):
Code:
+-----------------------------------------------------------------------------+
| 10,000,000 | 1st | 2nd | 3rd | 4th | 5th || Ave. |
|----------------------+--------+--------+--------+--------+--------++--------|
| String$ + CopyMemory | 2.6685 | 2.7969 | 2.6522 | 2.6635 | 2.6848 || 2.6932 |
|----------------------+--------+--------+--------+--------+--------++--------|
| SysReAllocStringLen | 1.7836 | 1.8095 | 1.7908 | 1.7901 | 1.7878 || 1.7924 |
+-----------------------------------------------------------------------------+
Code:
Option Explicit 'In a standard (.BAS) module
Private Declare Function QueryPerformanceCounter Lib "kernel32.dll" (ByRef lpPerformanceCount As Currency) As Long
Private Declare Function QueryPerformanceFrequency Lib "kernel32.dll" (ByRef lpFrequency As Currency) As Long
Private Declare Function SysReAllocStringLen Lib "oleaut32.dll" (ByVal pBSTR As Long, Optional ByVal pszStrPtr As Long, Optional ByVal Length As Long) As Long
Private Declare Sub CopyMemory Lib "ntdll.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private Declare Sub InitCommonControls Lib "comctl32.dll" ()
Private Sub Main()
Const ITERATIONS = 10000000 - 1
Dim iCharCodes() As Integer, I As Long, sBuffer As String
Dim Freq As Currency, Start(1) As Currency, Stop_(1) As Currency
InitCommonControls
ReDim iCharCodes(0 To 999) As Integer
SysReAllocStringLen VarPtr(sBuffer), , 1000& 'Allocate a buffer containing random data
CopyMemory iCharCodes(0&), ByVal StrPtr(sBuffer), 2000& 'and use it to populate the Integer array
sBuffer = vbNullString
MsgBox "Set Priority to Realtime to minimize interference from other processes.", vbInformation
QueryPerformanceFrequency Freq
QueryPerformanceCounter Start(0&)
For I = 0& To ITERATIONS
sBuffer = String$(1000&, 0)
CopyMemory ByVal StrPtr(sBuffer), iCharCodes(0&), 2000&
Next
QueryPerformanceCounter Stop_(0&)
sBuffer = vbNullString
QueryPerformanceCounter Start(1&)
For I = 0& To ITERATIONS
SysReAllocStringLen VarPtr(sBuffer), VarPtr(iCharCodes(0&)), 1000&
Next
QueryPerformanceCounter Stop_(1&)
sBuffer = "String$ + CopyMemory: " & FormatNumber((Stop_(0&) - Start(0&)) / Freq, 4&) & vbCrLf & _
"SysReAllocStringLen: " & FormatNumber((Stop_(1&) - Start(1&)) / Freq, 4&)
MsgBox sBuffer, vbInformation
End Sub
-
Feb 20th, 2019, 06:21 AM
#10
Re: [RESOLVED] CopyMemory a range of integer array values to create a string?
JFYI, clearing target var w/ sBuffer = vbNullString just before calling SysReAllocStringLen increases performance another 30%
Code:
String$ + CopyMemory: 1.6947
SysReAllocStringLen: 1.2316
SysReAllocStringLen w/ clear: 0.9585
cheers,
</wqw>
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|