Форум программистов, компьютерный форум, киберфорум
Visual Basic
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.73/11: Рейтинг темы: голосов - 11, средняя оценка - 4.73
1412 / 878 / 93
Регистрация: 08.02.2017
Сообщений: 3,753
Записей в блоге: 2

Возврат функцией по указателю

25.09.2023, 09:03. Показов 2743. Ответов 29
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Когда-то видел подобный вопрос и с тех пор как-то озадачился, так бы може х.з. Функции VB предназначены возвращать результат только по значению. Проведем небольшое исследование.
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
Sub testFunc()
    Dim s$
    s = "Hallo "
    Debug.Print VarPtr(Func(s))
'    Debug.Print StrPtr(Func(s))    
End Sub
 
Function Func$(arg$)
    Func = arg + "World"
    Debug.Print VarPtr(Func)
'   Debug.Print StrPtr(Func(s))
End Function
Как видим Varptr разный, Strptr одинаковый. Т.е. внутри функции, одна сущность переменной, "снаружи" другая, но указатель на данные во внешнюю записывается тот же. Сделаем так.
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
Sub testFunc()
    Dim s$
    s = "Hallo      "
    Debug.Print StrPtr(s)
    Debug.Print StrPtr(Func(s))
    Debug.Print s
End Sub
 
Function Func$(arg$)
    Mid$(arg, 7) = "World"
    CopyMemory ByVal VarPtr(Func), StrPtr(arg), 4
End Function
Как видим, мы передали строку функции, и получили ее же, но уже обработаную, без копирования. Также наверное можно сделать и с массивом.. Работает, правда, не очень стабильно, если выполнять пошагово - вызывает вылет.

Добавлено через 1 час 28 минут
Есть такая идея, что в переменой функции по умолчанию проинициализированая пустая строка и после смены указателя надо эту строку удалить с помощью heapfree или еще как и вылета не будет. Проверить пока не могу пишу с телефона

Добавлено через 4 часа 52 минуты
Идея плохая была, но есть есче одна, всвязи с чем вопрос, можно ли с помощью win-hex найти указатель на основную епеременную функции?

Добавлено через 1 минуту
Чтобы понять ее смещение относительно стека и др.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
25.09.2023, 09:03
Ответы с готовыми решениями:

Возврат строки из функции по указателю
Здравствуйте. Обьясните пожалуйсто, почему компилятор выдает предупреждение при выполнении следующего кода и почему строка возвращается не...

Проблемка с функцией пользователя и передачей параметров по указателю
Возникла проблемка с функцией пользователя и передачей параметров по указателю... Вот код, проблема выделена красным цветом: //...

Не могу вывести на экран строку, переданную по указателю функцией
Вот такой несложный код. Функция copyString просто копирует строку. #include "stdafx.h" #include <iostream> using...

29
1412 / 878 / 93
Регистрация: 08.02.2017
Сообщений: 3,753
Записей в блоге: 2
02.10.2023, 02:36  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от HackerVlad Посмотреть сообщение
так вот чем ты занимаешься
Всего лишь несколько строчек, и заблокированая почти вся доступная память (без WinApi!), очень быстро, не знаю, может где-то можно ипользовать )
Цитата Сообщение от testuser2 Посмотреть сообщение
Неверно. Вообще видимо вредно в функции использовать в качестве аргумента др. функции.
Также неверно. В общем, этот баг наверное касается только возвращаемых UDF динамических массивов.
0
1412 / 878 / 93
Регистрация: 08.02.2017
Сообщений: 3,753
Записей в блоге: 2
02.10.2023, 06:50  [ТС]
Причем баг не распространяется на массив, расположенный внутри типа.. То беж если функции задать тип UDT с дин. массивом внутри, то нет глюка с неосвободившейся памятью по завершению процедуры. Но появляется другой минус - нет автоматической передачи данных по ссылке, как в этом случае.
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
Type tpLongArray
    ar() As Long 
End Type
Sub test()
    Dim tla As tpLongArray  
 
    tla = GetTempLongArray
    Debug.Print VarPtr(tla.ar(0))    
End Sub
Function GetTempLongArray() As tpLongArray
    ReDim GetTempLongArray.ar(262144000)
    Debug.Print VarPtr(GetTempLongArray.ar(0))
End Function
Происходит двойное выделение памяти. 1я ступенька внутри функции, 2я - присвоение ее результата переменной.
Миниатюры
Возврат функцией по указателю  
0
1412 / 878 / 93
Регистрация: 08.02.2017
Сообщений: 3,753
Записей в блоге: 2
05.10.2023, 17:39  [ТС]
Есть еще один своеобразный момент, связаный с функциями, замеченый ранее, когда также пытался что-то бодяжить с функциями. Не знаю, если в этом, что-то интересное или практическое, но дело вот в чем. Если взят функцию заданную как массив и попытаться обратиться к элементу массива (закомментированая строчка), то выдаст ошибку. Если добавить еще пустые скобочки, то ошибки не бует, просто реверсивный вызов до безконечности переполнения стека вызовов.
Visual Basic
1
2
3
4
5
Function fnc1() As Variant()
    ReDim fnc1(0)
    fnc1()(0) = 0
'    fnc1(0) = 1
End Function
Вообще такие скобочки,могут быть иногда полезны, допустим, чтобы получить n-ый ключ из словаря (a = dict()(2)), хотя метод, конечно не очень оптимальный. Да еще, есть такое, если точно помню, когда обращаешься к другому процессу (Excel), то чтобы получить глобалку типа вариант из модуля книги, то надо вроде бы добавить к ней скобочки, т.е. получение переменной выглядит, как вызов функции.
0
1412 / 878 / 93
Регистрация: 08.02.2017
Сообщений: 3,753
Записей в блоге: 2
07.10.2023, 13:29  [ТС]
Цитата Сообщение от testuser2 Посмотреть сообщение
Глядя на код VBA Memory Tools, видно, что там довольно профессиональный досканально-скурпулезный подход, очнь много тестов, подчас многое не понятно. Понравились мне там конструкции типа MemByte(VarPtr(x1)) = MemByte(VarPtr(x2)). В данном случае это комбинация из парных свойств Property Let, и Property Get, и появилась идея поразбираться, как это работает. Кртакий вывод работает не очень хорошо если дело касается данных (строки, массивы) и именно это является одной из причин (возможно основной) медлительности левого Mid-а, который работает по такому же принципу, зашитому в VB. В чем подвох. В выражении
Visual Basic
Выделить код
1
Mid(s1, 3) = s2
s2 передается в функцию аналогично методу ByVal, т.е. сначала копируется во временную переменную, и только потом используется в функции, и при завершении фунции временная переменная удаляется полностью вместе с данными
Ссылку, точнее указательн в Property Let передать можно из другой функции. Возьмем такой пример.
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Property Let Prop1(arg1 As Long, arg2 As String)
    Debug.Print "Внутри Property Let"
    Debug.Print VarPtr(arg2)
    Debug.Print StrPtr(arg2); vbCr 'будет тот же самый указатель, что и Property Get
End Property
Property Get Prop1(arg1&) As String
    Prop1 = "abvgd"
    Debug.Print "Внутри Property Get"
    Debug.Print VarPtr(Prop1)
    Debug.Print StrPtr(Prop1); vbCr
End Property
 
Sub TestProp()
    Dim l&    
    Prop1(l) = Prop1(l)
End Sub
Добавлено через 16 минут
Я хотел проверить, можно ли ускорить таким образом левый Mid, т.е. передавать ему не переменную, а вывод другой функции, но обнаружилась проблема, с тем, что ссылку-то можно передать Mid-у, но он ее сожрет. Левая функция стирает любые данные, которые ей передают справа при заершении. Чтобы левая функция не съедала данные, нужно освобождать указатель переданной ссылки. С Mid конено ни чего не сделать, нутрь его не залесть. Если говорить о Property, то, допустим если надо передать (приспичило) переменную по ссылке в левую функцию (Let). Для этого добаим функцию, которая возвращает строку с указателем на те же данные, что и у аргумента (GetStrLink). Дополнительно в Property Let нужно добавить освобождение указателя, чтобы левая функция не затерла данные по этому указателю.
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Sub TestProp()
    Dim l&, s$
    s = "stroka"
    Debug.Print StrPtr(s)
    Prop1(l) = GetStrLink(s)
    
'    Debug.Print VarPtr(TestProb(l))  'покажет тот же указатель, что и у arg2 в Property Let
'    TestProp(l) = s                  's передастся в Property Let по значению
End Sub
Function GetStrLink(s As String) As String
    CopyMemory ByVal VarPtr(GetStrLink), StrPtr(s), 4
End Function
Property Let Prop1(arg1 As Long, arg2 As String)
    Debug.Print "Внутри Property Let"
    Debug.Print VarPtr(arg2)
    Debug.Print StrPtr(arg2); vbCr
    CopyMemory ByVal VarPtr(arg2), 0&, 4 'обнуляем (освобождаем) указатель    
End Property
0
1412 / 878 / 93
Регистрация: 08.02.2017
Сообщений: 3,753
Записей в блоге: 2
08.10.2023, 04:38  [ТС]
"И ты LSet?!"
Грустная правда, LSet тоже копирует и уничтожает данные, а ведь все могло быть быстрее, будь это простые функции с byref аргументами..
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
Private Sub testleftSids()
    Dim s1$, s2$
    s1 = "sfafaf"
    s2 = "dfd"
    Stop
'    Mid$(s1, 1) = GetStrLink(s2)
    LSet s1 = GetStrLink(s2)
    Stop                         'см. в Locals, в s2 мусор, данные затираются после Mid и после LSet.
    GetMem4 0&, ByVal VarPtr(s2)
End Sub
Public Static Function GetStrLink(s As String) As String
    GetMem4 StrPtr(s), ByVal VarPtr(GetStrLink) 
End Function
0
1412 / 878 / 93
Регистрация: 08.02.2017
Сообщений: 3,753
Записей в блоге: 2
10.10.2023, 05:02  [ТС]
Пару слов о присвоении разных типов, при которых происходит автоматическая конвертация. В vba можно получить массив с листа Excel в переменную типа вариант, либо в массив типа вариант. При копировании с листа 300 мб массива вот что происходит в том и др. случае.
Code
1
2
3
4
До выполнения макроса        355612          
Метод      Working Set Peak Working Set Время (с)        
arr() = .Value  665180      978848       4,1875
arr = .value    668212      673124       3,625
Кликните здесь для просмотра всего текста
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
Sub ЗаполнениеТаблицы() 'единицами
    Workbooks("Книга1").Sheets(1).Range(Columns(1), Columns(19)).Value = 1
End Sub
Sub TestBigData2() '1048576*19*16 = 318767104 = 304 мб    
    t! = Timer
    With Workbooks("Книга1").Sheets(1).Range(Columns(1), Columns(19))
'        arr() = .Value
        arr = .Value
    End With
    t = Timer - t
    Debug.Print t
End Sub

Как видно, в вариант копиурется быстрее. При получении данных в массив со скобочками происходит конвертация с дополнительным копированием, хотя фактически можно было бы лишь переместить ссылку на массив из варианта в переменную массива.
0
933 / 366 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
20.11.2023, 10:22
Цитата Сообщение от testuser2 Посмотреть сообщение
Как видно, в вариант копиурется быстрее
получил тот же вывод ещё на заре своего VBAшного опыта — на Планете. Действительно, получение массива в вариативную переменную происходит быстрее, чем в переменную массива, а также не вызывает ошибку при передаче единственного значения (но нужно проверять вариативную на IsArray() ) — очень важно в цикле по областям диапазона.
0
Модератор
10069 / 3914 / 886
Регистрация: 22.02.2013
Сообщений: 5,863
Записей в блоге: 79
20.11.2023, 10:27
Копирование в Variant массива быстрее, но и доступ к элементам в этом случае медленней. Копирование в массив Variant'ов медленнее, но и доступ во много раз быстрее. В одном случае проверяется содержится ли в Variantе массив, и если содержится то получается доступ к этому массив каждый раз когда идёт обращение к элементу из массива. Массив типа Variant - это уже сам по себе SafeArray массив и доступ осуществляется также быстро как и к обычному массиву.
1
933 / 366 / 43
Регистрация: 10.05.2021
Сообщений: 1,564
Записей в блоге: 10
20.11.2023, 10:45
The trick, всё правильно, только доступ медленнее совсем незначительно и, если с данными предстоит серьёзная работа (например, со строками), то обязательно нужно пересобрать в массив нужного типа
0
1412 / 878 / 93
Регистрация: 08.02.2017
Сообщений: 3,753
Записей в блоге: 2
20.11.2023, 15:49  [ТС]
Jack Famous, в общем вывод я сделал такой, что технически более правильно получать массив с листа в вариантную переменную, поскольку при этом не происходит преобразования и повторного копирования мссива. А после этого можно переместить ссылку на массив в переменную типа массив. С CopyMemory это будет выглядеть так. (однако учитывая медлительность CopyMemory в x64 vba пример не очень хороший).

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#If Win64 Then
   Const ptrSz As LongPtr = 8
#Else
   Const ptrSz As LongPtr = 4
#End If
Const ptr0 As LongPtr = 0
Sub Пример()
    
    Dim Var, Arr()
    Var = Range("A1:A10000")
    CopyMemory ByVal ArrPtr(Arr), ByVal VarPtr(Var) + 8, ptrSz 'копируем ссылку на массив из варианта в переменную массива
    CopyMemory ByVal VarPtr(Var) + 8, ptr0, ptrSz 'зануляем ссылку в варианте
    '***
End Sub
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
20.11.2023, 15:49

Возврат объекта функцией
class C { int c; }c1,c2; C func() { return c1; }

Возврат значения функцией
Суть состоит в том, что когда я хочу вивести значение t в теле main выводится 0. Кто знает что я не так пишу? #include <stdio.h> ...

Возврат значения функцией
Может ли функция вернуть (return) 2 переменных одновременно?

Возврат функцией указателя на функцию
Всем привет! У меня возникла такая проблема: класс имеет поле-указатель на функцию. В методе, который осуществляет доступ к этуму полю,...

Возврат функцией массива структур
Пишу программу, которая в зависимости от выбора пользователя считывает информацию о студентах, вводимую с клавиатуры, либо использует...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
30
Ответ Создать тему
Новые блоги и статьи
Транслитерация текста с кириллицы на латиницу (вариант №2)
Maks 13.11.2026
Обновленная версия ранее созданной обработки. Добавлено: - Проверка исходного текста на кириллицу, через обращение к стандартной функции "ТолькоКириллицаВСтроке" из общего модуля. . .
Часы с термометром и праздничным календарем
yariko 12.11.2026
Сегодня мы рассмотрим как можно сделать отличные многофункциональные часы. Итак, поставим конкретную задачу: разработать часы с календарем, двумя термодатчиками, выводом поздравительных сообщений. . .
Транслитерация текста с кириллицы на латиницу (вариант №1)
Maks 11.11.2026
Решил облегчить жизнь себе и коллегам админам при создании электронных почтовых ящиков для пользователей, в результате написал обработку "Транслитерация текста" с кириллицы на латиницу, а в ней. . .
Книги по геймдизайну, левел-дизайну, игровым механикам и проектированию игрового опыта
8Observer8 08.11.2026
Содержание блога | English Version 1. 2003 - 06 - Designing Virtual Worlds (1st Edition) Автор: Richard A. Bartle | Объем: 768 стр. Ссылки: Amazon . . .
Родители токсичные абьюзеры по отношению к своим детям ругают их оскорбляют не любят
zorxor 08.11.2026
Жить в атмосфере постоянных оскорблений, критики и холодности со стороны родителей — это тяжелое и болезненное испытание, которое оставляет глубокие эмоциональные раны. Токсичное и абьюзивное. . .
Как только я захожу к себе в свою комнату я сразу же с себя снимаю свои трусы. Ответ от Джемени ИИ.
zorxor 08.11.2026
Джемени, как только я захожу к себе в свою комнату я сразу же с себя снимаю свои трусы. Многие люди, возвращаясь домой, сразу переодеваются в максимально свободную одежду или вовсе предпочитают. . .
Паттерн очереди действий/команд (Action / Command Queue). Система очереди действий и кат-сцен с SDL3 Callbacks, cglm и OpenGL
8Observer8 07.11.2026
Содержание блога | English Version Руководство для начинающих по реализации паттерна очереди действий/ команд (Action / Command Queue) на C++ (C++20) с использованием официального SDL3 Callbacks. . .
Проверка полного ФИО в типовом справочнике
Maks 07.11.2026
Решение реализовано в конфигурации КА2, на примере справочника "КонтактныеЛицаПартнеров". Задача: Запрет инициалов. Не допускаеть использование сокращений вида "И. И. ", "И. И. ", "И И" и. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru