Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443

Тонкости передачи параметров в функции и процедуры

30.04.2020, 23:29. Показов 8821. Ответов 30

Студворк — интернет-сервис помощи студентам
Вот 2 приблизительно одинаковых простеньких примерчика на VB:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Option Explicit
 
Function Myfunction(ByRef B As Long) As Long
  MsgBox (Str$(B))
End Function
 
Private Sub Form_Load()
  Dim A As Long
 
  A = 5
  Myfunction (A)
End Sub
 
'Результат: 5
Функция Myfunction просила передать ей параметр по ссылке, мы передали - положили в стек адрес переменной A.

======================================== =============

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Option Explicit
 
Function Myfunction(ByRef B As Long) As Long
  MsgBox (Str$(B))
End Function
 
Private Sub Form_Load()
  Dim A As Long
 
  A = 5
  Myfunction (VarPtr(A))
End Sub
 
'Результат: 1703444
Функция Myfunction просила передать ей параметр по ссылке, а мы сделали OVERRIDE и передали ей параметр по копии (ByCopy), поскольку VarPtr(A) это выражение. По идее, компилятор должен был вычислить значение этого выражения, разместить результат (а это адрес переменной А) в каком-то месте памяти и передать адрес этого места памяти в стек. Но всё равно в стеке вроде бы должен оказаться адрес переменной А, как и в первом случае. Почему же результат разный?
0
Лучшие ответы (1)
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
30.04.2020, 23:29
Ответы с готовыми решениями:

Способы передачи параметров в процедуры
Доброго времени суток! Уже который день пытаюсь разобраться с ранее неизвестным мне языком программирования ассемблером. Что-то, вроде,...

Использование указателей для передачи параметров функции
Ели мы объявляем формальный параметр как указатель,тогда ведь нам при вызове этой функций следует передать аргумент предварив его &...

функции в языке с: (использовать механизм передачи параметров по ссылке)
реализовать функцию, осущ. поиск в целочисленном массиве 4-го максимума и 3-го минимума. В качестве параметров функции выступают массив и...

30
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
03.05.2020, 21:31  [ТС]
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от Power_Basic
Это намёк на то, что так никогда не бывает?
Цитата Сообщение от The trick Посмотреть сообщение
Не бывает
Приятно это слышать

Цитата Сообщение от The trick Посмотреть сообщение
за исключением структур с фиксированным буфером.
Их тоже приходится передавать как строковые аргументы фиксированной длины?

Цитата Сообщение от Power_Basic
Несколькими постами раньше я уже приводил пример того, как от нас требую отправить параметр AS WSTRINGZ.
Цитата Сообщение от The trick Посмотреть сообщение
И что? Не пойму в чем проблема... Как раз нужно 2 раза вызывать.
Ну если 2 раза вызывать, тогда проблема уже не такая большая, конечно. Ну просто я первый раз столкнулся с такой ситуацией.

Цитата Сообщение от Power_Basic
Ну то есть опять-таки надо явно задавать значение N.
Цитата Сообщение от The trick Посмотреть сообщение
Не обязательно. Выделяйте динамический буфер и ссылайтесь на него через WSTRINGZ (если так можно в PB)
Динамический буфер это массив байт что ли? Или динамическая строка?
0
Модератор
10061 / 3906 / 885
Регистрация: 22.02.2013
Сообщений: 5,856
Записей в блоге: 79
03.05.2020, 21:48
Цитата Сообщение от Power_Basic Посмотреть сообщение
Их тоже приходится передавать как строковые аргументы фиксированной длины?
Посмотрите например на структуру LOGFONT поле lfFaceName.

Цитата Сообщение от Power_Basic Посмотреть сообщение
Ну просто я первый раз столкнулся с такой ситуацией.
Довольно-таки часто такая ситуация встречается в WINAPI. К примеру в CryptoAPI.

Цитата Сообщение от Power_Basic Посмотреть сообщение
Динамический буфер это массив байт что ли? Или динамическая строка?
Да без разницы, я не знаю как там в Power Basic'е с этим делом. В C++ к примеру просто выделяешь буфер WCHAR (CHAR) И кастуешь на него указатель LP(W)STR. Это на самом низком уровне, без вспомогательных классов. В VB6 проще просто передать строковой буфер выделенный через Space Или String.
0
63 / 48 / 12
Регистрация: 28.12.2014
Сообщений: 270
04.05.2020, 11:31
Цитата Сообщение от Power_Basic Посмотреть сообщение
Ну они-то просят указатель именно на фиксированные.
Если вы имеет ввиду под словом они – документация на win API функции, то для того же Си, const перед именем параметра в прототипе функции означает, что вызываемая функция не модифицирует значение аргумента. И это не говорит о том, что срока должна быть объявлена как строка фиксированной длины - это особенность СИ. Для win api нужны 1-байтные и юникодные СИ строки. Их можно создавать как угодно, главное, чтобы формат для вызываемой функции был верен.

Цитата Сообщение от Power_Basic Посмотреть сообщение
PureBasicВыделить код1
Dim MyStr AS WSTRINGZ * N
Для VB такая запись говорит, что значение N является константой, которая должна быть определена на этапе компиляции. Если значение N известно на этапе компиляции, то вместо N нужно указать литеральную константу. Если значение N на этапе компиляции неизвестно, то объявляется динамическая строка, длина которой и буфер под которую выделяется при присвоении величины переменной во время выполнения приложения.

Если в структуре на СИ указана массив символов CHAR WCHAR, то строковое поле нужно в VB объявить как строковое поле постоянной длины или массив байт. Для строки с постоянной длиной, данные строки будут храниться в самой структуре, если объявить поле как динамическую строку, то в данном поле будет записан указатель на строку, а не строковые данные. Совсем не то, что будет ожидать СИ функция. Подробнее можно почитать Эплман стр. 881, если есть желание.
1
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
04.05.2020, 23:48  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
В VB6 проще просто передать строковой буфер выделенный через Space Или String.
Ну я же именно так и делал, на самом деле

Вот фрагмент из той программы:

PureBasic
1
2
3
4
5
6
7
8
9
10
11
FUNCTION PBMAIN () AS LONG
  dim RESULT AS LONG
  dim mszExpandedPathList AS ASCIIZ * 10000
  dim pcchPathListLength AS DWORD
 
  mszExpandedPathList = string$(10000, $nul)
  pcchPathListLength = 10000
 
  RESULT = PdhExpandWildCardPathA ("", "\Процессор(*)\*процессора", _
           mszExpandedPathList, pcchPathListLength, %PDH_NOEXPANDCOUNTERS)
END FUNCTION
Это не VB, это PowerBasic, но для рассматриваемого вопроса принципиальной разницы нет.
Вот тогда-то и возникло неприятное чувство, что размер буфера (в данном случае я выбрал величину 10000 байт) приходится "снимать с потолка". Выбирал "с запасом", чтобы уже наверняка

Ну да ладно, это не самый важный вопрос во всей этой "музыке". Работает, ну вот и хорошо.

Цитата Сообщение от IDK Посмотреть сообщение
Если вы имеет ввиду под словом они – документация на win API функции, то для того же Си, const перед именем параметра в прототипе функции означает, что вызываемая функция не модифицирует значение аргумента. И это не говорит о том, что срока должна быть объявлена как строка фиксированной длины - это особенность СИ. Для win api нужны 1-байтные и юникодные СИ строки. Их можно создавать как угодно, главное, чтобы формат для вызываемой функции был верен.
Цитата Сообщение от IDK Посмотреть сообщение
Если в структуре на СИ указан массив символов CHAR WCHAR, то строковое поле нужно в VB объявить как строковое поле постоянной длины или массив байт. Для строки с постоянной длиной, данные строки будут храниться в самой структуре, если объявить поле как динамическую строку, то в данном поле будет записан указатель на строку, а не строковые данные. Совсем не то, что будет ожидать СИ функция..
Большое спасибо, очень полезная для меня информация.
Теперь мне, по крайней мере, стало понятно, что подразумевается под обозначением const и WCHAR в комментах заголовочного файла, фрагмент из которого я процитировал выше и для удобства процитирую здесь ещё раз:

PureBasic
1
2
3
4
5
   METHOD Speak ( _                                     ' VTable offset = 80
     BYREF pwcs AS WSTRINGZ _                           ' __in const WCHAR *pwcs
   , BYVAL dwFlags AS DWORD _                           ' __in DWORD dwFlags
   , BYREF pulStreamNumber AS DWORD _                   ' __out ULONG *pulStreamNumber
   ) AS LONG                                            ' HRESULT
Цитата Сообщение от IDK Посмотреть сообщение
Подробнее можно почитать Эплман стр. 881, если есть желание.
Нашёл, начал читать, поробую разобраться.

Добавлено через 1 час 47 минут

Не по теме:

А вот интересно, я смотрю какой-то трусливый аноним прикрепил к этой ветке метку "глупые заблуждения". Аноним, давай уже выскажись аргументированно. Обсудим. Если заблуждения, то обязательно глупые, так что ли? Сам-то ты хоть умный или только таким прикидываешься? :)



Добавлено через 8 минут

Не по теме:

И вопрос к модераторам.
Эдак любой аноним может к чужим темам оскорбительные метки прицеплять?
Слово "глупые" на всех форумах считается оскорбительным.



Добавлено через 4 часа 30 минут

Не по теме:

Да ладно, пошутил я :)
Мне, по большому счёту, пофиг, что там в метках написано.
Мои заблуждения, и правда, пожалуй глупые, поскольку я ни разу не профессионал, а "продвинутая домохозяйка", и мне по статусу положено говорить глупости время от времени :)

0
63 / 48 / 12
Регистрация: 28.12.2014
Сообщений: 270
05.05.2020, 04:32
Цитата Сообщение от Power_Basic Посмотреть сообщение
BYREF pwcs AS WSTRINGZ _                           ' __in const WCHAR *pwcs
В VB я бы объявил данный параметр как ByVal pwcs As Long, если бы это была бы нативная функция а не интерфейсная, из VB вызов бы выполнил бы так: Speak(StrPtr(pwcs),...). Для VB ваша запись неверна. Как для PB не знаю.

Добавлено через 9 минут
В VB передавать строку "BYREF pwcs AS WSTRINGZ" можно если только вызываемая функция поддерживает oleautomation, СИ функции, как правило, его не поддерживают, с помощью ByRef вы передаете в вызываемую функции указатель на заголовок BSTR строки, содержащий длину строки, а не указатель на содержимое строки. Формат СИ строки и BSTR можно посмотреть в MSDN.

Цитата Сообщение от Power_Basic Посмотреть сообщение
Ну я же именно так и делал, на самом деле
Для VB "mszExpandedPathList = string$(10000, $nul)" - это не обязательно, буфер уже создан и инициализирован т.к. строка фиксированной длины, для строки переменной длины это сделать необходимо, иначе в вызываемую функцию будет передан нулевой указатель. Функцию PdhExpandWildCardPathA нужно вызывать дважды, для того, чтобы получить размер буфера. Ваш вариант тоже, но не оптимальный.
0
Модератор
10061 / 3906 / 885
Регистрация: 22.02.2013
Сообщений: 5,856
Записей в блоге: 79
05.05.2020, 09:43
Цитата Сообщение от IDK Посмотреть сообщение
с помощью ByRef вы передаете в вызываемую функции указатель на заголовок BSTR строки, содержащий длину строки, а не указатель на содержимое строки.
Нет. При передаче ByRef передается BSTR*. Передается указатель на указатель на строку, а не на заголовок. Заголовок хранится по смещению -4.
1
05.05.2020, 10:47

Не по теме:

Цитата Сообщение от The trick Посмотреть сообщение
Нет. При передаче ByRef передается BSTR*. Передается указатель на указатель на строку, а не на заголовок. Заголовок хранится по смещению -4.
Согласен. Вижу, что это так.

0
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
05.05.2020, 17:21  [ТС]
Цитата Сообщение от IDK Посмотреть сообщение
Для VB ваша запись неверна. Как для PB не знаю.
Ну это я уже давно понял, что для VB такой подход не годится. Компилятор меня обругал нехорошими словами
А что касается PowerBasic'а, то я уже говорил в одном из предыдущих постов, что по какой-то причине у всех поклонников этого диалекта "модно" передавать этот параметр в функцию Speak именно так
По всей видимости, во времена SAPI 5.0 и первых версий компилятора PB такой неуклюжий подход был единственно возможным. Ну вот с тех пор и копируют эту тяжеловесную конструкцию из программы в программу вплоть до наших дней по принципу "ну оно же прекрасно работает, ну и зачем что-то менять"

Цитата Сообщение от IDK Посмотреть сообщение
Для VB "mszExpandedPathList = string$(10000, $nul)" - это не обязательно, буфер уже создан и инициализирован т.к. строка фиксированной длины, для строки переменной длины это сделать необходимо, иначе в вызываемую функцию будет передан нулевой указатель. Функцию PdhExpandWildCardPathA нужно вызывать дважды, для того, чтобы получить размер буфера. Ваш вариант тоже, но не оптимальный.
Ну да, я согласен, это уже для перестраховки было тогда сделано, на эмоциях
Отсюда и такая огромная цифра, снятая с потолка по принципу "да на обожрись, только отстань от меня со своим буфером!"
Там в семействе функций WINAPI PDH приходится сразу к нескольким функциям обращаться, чтобы в конечном итоге значение счётчика производительности получить. Ну вот оно всё вместе и не получалось тогда очень долго.
Ну а сейчас, оглядываясь назад, всё выглядит довольно лёгким и очевидным.
И даже скажу больше, мне эта функция в конечном итоге вообще не понадобилась, но просто она сохранилась в черновиках, ну вот и привёл её в качестве примера, когда заранее требуется указывать размеры принимающего информацию буфера.
0
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
08.05.2020, 16:26  [ТС]
Цитата Сообщение от IDK
В VB я бы объявил данный параметр как ByVal pwcs As Long, если бы это была бы нативная функция а не интерфейсная, из VB вызов бы выполнил бы так: Speak(StrPtr(pwcs),...). Для VB ваша запись неверна. Как для PB не знаю.
Цитата Сообщение от Power_Basic Посмотреть сообщение
Ну это я уже давно понял, что для VB такой подход не годится. Компилятор меня обругал нехорошими словами
А что касается PowerBasic'а, то я уже говорил в одном из предыдущих постов, что по какой-то причине у всех поклонников этого диалекта "модно" передавать этот параметр в функцию Speak именно так
По всей видимости, во времена SAPI 5.0 и первых версий компилятора PB такой неуклюжий подход был единственно возможным. Ну вот с тех пор и копируют эту тяжеловесную конструкцию из программы в программу вплоть до наших дней по принципу "ну оно же прекрасно работает, ну и зачем что-то менять"
И всё-таки я был не прав, пожалуй. Буржуи не такие тупые, как это показалось нашему покойному сатирику
И это не слепое копирование из программы в программу, а вполне резонное.
Если строки маленькие, тогда пофиг, конечно, пусть компилятор копирует нашу строку в какое-то место динамической памяти и передаёт в Speach API ссылку на эту копию.
А если строка огромная?!
Тогда имеем в памяти саму строку (оригинал) и копию строки одновременно, а это уже не хорошо хотя бы с точки зрения хорошего стиля.
Как вариант можно было бы вроде бы сразу же удалить оригинал, и тогда в памяти у нас снова только одна строка. Но мы это слелать не можем, потому что в дефолтном варианте вызова функции Speak вызывающий код блокируется вплоть до завершения работы вызываемого. Ну то есть так и останутся у нас в памяти надолго две огромные строки одновременно.

PureBasic
1
2
obj_IspVoice.Speak(BYVAL STRPTR(str_Temp), %SPF_DEFAULT, dwrd_ulStreamNumber)
' одна огромная строка в памяти
PureBasic
1
2
obj_IspVoice.Speak((str_Temp), %SPF_DEFAULT, dwrd_ulStreamNumber)
' две строки огромные в памяти
0
Модератор
10061 / 3906 / 885
Регистрация: 22.02.2013
Сообщений: 5,856
Записей в блоге: 79
09.05.2020, 09:39
Power_Basic, а в чем проблема без скобок передать? Для чего какие-то лишние действия? В VB6 ты просто передаешь строку и никаких копий не создается.
0
 Аватар для Power_Basic
46 / 25 / 0
Регистрация: 08.03.2016
Сообщений: 443
09.05.2020, 17:14  [ТС]
Цитата Сообщение от The trick Посмотреть сообщение
Power_Basic, а в чем проблема без скобок передать? Для чего какие-то лишние действия? В VB6 ты просто передаешь строку и никаких копий не создается.
Сейчас для меня VB6 это своего рода "транзитный" язык, с помощью которого я могу коммуницировать с программистами других диалектов бейсика, но пишу-то я программы всё-таки на PowerBasic'е. Ну так получилось, что именно в изучении этого языка я продвинулся дальше чем в изучении всех прочих. Большинство вопросов, затрагиваемых в том числе и в этой ветке, универсальны для всех диалектов бейсика. Поэтому мне надо разобраться, как это (в данном случае передача параметров) вообще работает (понять сам механизм), ну а потом воплотить свои замыслы всё-таки именно в PowerBasic'е, а там простая передача динамической строки не срабатывает:
Тонкости передачи параметров в функции и процедуры

Но на самом деле, теперь это не такой уж и важный вопрос, чтобы на нём так подробно останавливаться. Главное, что я уже понял, как это в принципе работает и мне этого вполне достаточно.
Просто я высказал неверное предположение в одном из своих предыдущих постов, ну вот и, вроде как, принёс свои извининения.

По правде сказать, сейчас у меня началась новая интенсивная фаза "допиливания" моего Аудио_бук_мейкера, поэтому мне вот прямо сейчас не до тонкостей теории
Хочется побыстрее воплотить несколько свежих идей и посмотреть, что из этого получится.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
09.05.2020, 17:14

Способы передачи параметров в функции. Реализация динамических двумерных массивов
в программе написать функции для сортировки массива. Подсчитать количество перестановок элементов массива при выполнении сортировки;

Процедуры и функции без параметров.
Вычислить среднее арифметическое значение элементов массива, в котором максимально 30 целочисленных элементов. Собственно...

Процедуры и функции без параметров: Из массива удалить последний из четных элементов
Из массива удалить последний из четных элементов. Пример: из массива A: 1 3 4 5 6 должен получиться массив A: 1 3 4 5.

Нужно заменить процедуры с параметрами, на процедуры без параметров
program p20A; uses CRT; type mas=array of integer; var X,Y: mas; N,i,m: integer; procedure zm (var q:mas); var a,b:...

Программа передачи параметров
НАПИСАНИЕ ПРОГРАММЫ ПЕРЕДАЧИ ПАРАМЕТРОВ С ПОМОЩЬЮ параметров командной строки


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

Или воспользуйтесь поиском по форуму:
31
Ответ Создать тему
Опции темы

Новые блоги и статьи
Эксперимент с картинкой-обложкой на CodinGame
Adler 10.07.2026
Решил на днях провести эксперимент. У меня есть аккаунт на CodinGame, ТОП-3 по РФ среди 2200 участников (в разделе соревнования по программированию ИИ-ботов). Там есть обложка, куда можно влепить. . .
После бана на Пикабу не работает авторизация аккаунта с Яндекса.
Hrethgir 09.07.2026
В частности https:/ / auto. ru/ logbook/ zapret-na-vozhdenie-posle-65-let_1cf28789-07b4-4c75-a2f7-4cd4edf9deeb тут хотел оставить комментарий такой Зрите в корень - монополизация на разработку программ. . .
GitDOS: Когда я решил скрестить MS-DOS, GitHub и Claude
MaGz GoLd 08.07.2026
Привет, Киберфорум! Хочу поделиться своим проектом, который, надеюсь, вас заинтересует. GitDOS — это веб-приложение, которое позволяет запускать DOS в браузере с тремя крутыми фичами: диски живут в. . .
Учебный мини "цифровой двойник" = (Сервер = Java + Flask_питон )+(3D = Гугловскаая 4T nvideo + google colab) +( WMS = Odoo на Docker)
anaschu 07.07.2026
Увидел в требованиях к вакансии создателя имитационных моделей связку (REst + Api + WMS + Anylogic + питон + 3D Nvideo), и решил посмотреть, что это такое. Из этого всего я работал более менее. . .
Море в объективе
kumehtar 06.07.2026
Хотел написать много проникновенных слов, но передумал. Оно само - говорит. Кто слышит тот слышит.
Doom для терминала без стрельбы и монстров. 3D Raycasting на ascii.
dcc0 05.07.2026
Попросил нейронную сеть deepai. org написать рейкастинг 3D с библиотекой ncurses для Linux. Чтобы можно было ходить на стрелочки. Чтобы стены были отрисованы символами. Справилась. Первый вариант. . .
Установка статуса документа по условию
Maks 05.07.2026
Алгоритм из решения ниже реализован на нетиповом документе "НарядПутевка" разработанного в КА2. Задача: в табличной части "Материалы" документа при записи автоматически устанавливать статус. . .
Сезонность и суточность закисления почв
anaschu 04.07.2026
200 часов это все равно моловато. Есть ситуации, но нестандартные, когда смена происходит за 5 лет. Но обычно это 50 лет и более. Наверное, закисление почвы происходит сезонно в средней. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru