В Excel VBA я могу использовать RtlCopyMemory
, чтобы переместить каждый элемент в 2D SafeArray of Variants в другой SafeArray of Variants таким образом, чтобы элементы были транспонированы.
Следующий фрагмент VBA отлично работает дляэто (при условии, что переменные имеют соответствующие значения):
For i = 0 To TotalElems - 1
CopyMemory ByVal ptrDest + i * LenElem, ByVal ptrSrc + (Elems1D * col + row) * LenElem, LenElem
col = col + 1
If col = Elems2D Then
col = 0
row = row + 1
End If
Next
Однако, я был разочарован скоростью выполнения.Приведенный выше фрагмент примерно в пять раз медленнее, чем простое использование VBA для присваивания значений, по одному, второму массиву.
Массивы могут быть большими;в них может быть много тысяч элементов.
Я предполагаю, что тысячи вызовов RtlCopyMemory
стоят дорого.
Поэтому я хотел проверить, переносит ли приведенный выше фрагмент на C / C ++DLL и вызов ее один раз (вместо тысяч раз) устранит узкое место и, возможно, будет даже быстрее, чем назначение значений непосредственно в VBA.
Я чрезвычайно заржавел на C / C ++, но справился со следующим.Но это не работает.Он возвращает «1», и Excel не падает.Но значения в массиве назначения не нарушаются кодом.Как будто ничего не произошло вообще.
long int __stdcall TransposeMemory(long *ptrDest, long *ptrSrc, long &LenElem, long &Elems1D, long &Elems2D, long &TotalElems) {
long col = 0;
long row = 0;
for (long i = 0; i < TotalElems; i++) {
memcpy (&ptrDest + (i * LenElem), &ptrSrc + (Elems1D * col + row) * LenElem, LenElem);
col++;
if (col == Elems2D) {
col = 0;
row++;
}
}
return 1;
}
В VBA я называю это так:
Result = TransposeMemory(array2(1, 1), array1(1, 1), LenElem, Elems1D, Elems2D, TotalElems)
Передача массивов таким образом дает функции DLL C / C ++ указательк первому элементу в каждом массиве.Все данные хранятся непрерывно, и каждый элемент имеет длину 16 байтов.
Можете ли вы показать мне, где я ошибаюсь?
В качестве дополнительного вопроса, какой метод будет выполнять эти данныесамое быстрое преобразование?
Чтобы прояснить расположение данных, представьте диапазон ячеек в Excel в строках и столбцах:
+---+---+---+
| a | e | i |
+---+---+---+
| b | f | j |
+---+---+---+
| c | g | k |
+---+---+---+
| d | h | l |
+---+---+---+
Приведенный выше 2D-массив состоит из четырех строк и трех столбцов иExcel отобразит его на рабочем листе по приведенному выше шаблону.
Однако VBA хранит значения непрерывно, начиная с первого элемента, как этот (каждый элемент имеет длину 16 байт):
+---+
| a |
+---+
| b |
+---+
| c |
+---+
| d |
+---+
| e |
+---+
| f |
+---+
| g |
+---+
| h |
+---+
| i |
+---+
| j |
+---+
| k |
+---+
| l |
+---+
Когда данные транспонированы правильно (и фрагмент кода VBA в верхней части этого вопроса делает именно это), Excel отображает их следующим образом:
+---+---+---+---+
| a | b | c | d |
+---+---+---+---+
| e | f | g | h |
+---+---+---+---+
| i | j | k | l |
+---+---+---+---+
Обратите внимание, что теперь у нас есть три строки и четыре столбца.
VBA хранит элементы в транспонированном массиве в следующем порядке, чего я и пытаюсь достичь:
+---+
| a |
+---+
| e |
+---+
| i |
+---+
| b |
+---+
| f |
+---+
| j |
+---+
| c |
+---+
| g |
+---+
| k |
+---+
| d |
+---+
| h |
+---+
| l |
+---+