Страница: 1 |
To sne: >>Это я к тому, что если есть возможность, то желательно использовать ByVal... посмотри: http://www.mvps.org/vb/hardcore/html/anatomyofbasicprocedurecall.htm Всем спасибо. Особенно digitin. To sne: Ну ты понимаешь, что это на обратный вывод наталкивает? "Пользуйте по возможности ByRef, так как для чисел - это не важно, а для String, и Variant это играет огромную роль" Страница: 1 |
Вопрос: Что значит ByVal и ByRef?
Добавлено: 29.05.04 11:33
Автор вопроса:
RomMario
У мня в книге написано, что ByVal это передача параметра по значению, а ByRef по ссылке, и тут же приводится пример где при передаче параметра ByVal передается адрес: VarPtr(i) и все работает, так почему ByVal называет по значению ну и наоборот???
Ответы
Всего ответов: 13
Номер ответа: 1
Автор ответа: Satrapp
ICQ: 75556561
Вопросов: 8
Ответов: 80
Профиль | | #1
Добавлено: 29.05.04 13:39
ByVal приводит к тому, что для вводимой за ним переменной при вызове процедуры создаётся копия, которая исчезает по окончании работы процедуры и никак не может повлиять на значение переменной, для которой эта копия создаётся.
Для переменной ByRef (даётся по умолчанию) копия не создаётся. Значение переменной ByRef процедура может изменить, а значение переменной ByVal – нет.
Номер ответа: 2
Автор ответа: sne
Разработчик Offline Client
ICQ: 233286456
Вопросов: 34
Ответов: 5445
Web-сайт:
Профиль | | #2
Добавлено: 29.05.04 15:02
ByRef (By Reference - по ссылке)
ByVal (By Value - по значению)
' mov eax, [esp+4]
' mov ecx, [eax]
' add ecx, 1
Private Sub a(l As Long)
l = l + 1
End Sub
' mov eax, [esp+4]
' add eax, 1
Private Sub b(ByVal l As Long)
l = l + 1
End Sub
Как можно видеть передача параметра ByRef, заносит в регистр ecx (в данном случае) ссылку на реальное значение... Это лишняя операция, и именно по этому существует мнение что передача по значению осуществляется быстрее... хотя одна операция с регистрами много код не замедлит (imho)
Номер ответа: 3
Автор ответа: Sharp
Лидер форума
ICQ: 216865379
Вопросов: 106
Ответов: 9979
Web-сайт:
Профиль | | #3
Добавлено: 29.05.04 16:09
> заносит в регистр ecx (в данном случае) ссылку на реальное значение...
Ты уверен? Обычно ведь при передаче по ссылке в стек кладется 4-байтовый адрес структуры или Unicode-строки или числа в памяти, а при передаче по значению само число кладется в стек, либо 4-байтовый адрес строки, скопированной как ASCIIZ... Сомневаюсь, что ByRef передает адрес через ECX, ведь API их вполне нормально принимают...
Номер ответа: 4
Автор ответа: sne
Разработчик Offline Client
ICQ: 233286456
Вопросов: 34
Ответов: 5445
Web-сайт:
Профиль | | #4
Добавлено: 29.05.04 16:29
Sharp, ты наверное меня несколько не понял, или я неясно выразился
Это не ByRef заносит/передает, а при использовании ByRef используется еще один регистр и совершается еще одна операция...
Это я к тому, что если есть возможность, то желательно использовать ByVal...
Т.е. при ByRef в стек положили адрес, по этому адресу отокопали число и уже только тогда с ним можно работать (тут прибавляется 1).
А при ByVal, в стеке уже все готовенькое, берем и используем ))
А про есх, с тем же успехом тут можно было написать mov eax, [eax]...
PS
Это отдизасемблированный код... и я не намерен сомневаться в его истинности ))
PPS
Возможно я и не прав... но по-моему все правда :D
Номер ответа: 5
Автор ответа: sne
Разработчик Offline Client
ICQ: 233286456
Вопросов: 34
Ответов: 5445
Web-сайт:
Профиль | | #5
Добавлено: 29.05.04 16:45
А, понял к чему это ты... это я не туда фразу ткнул
Сейчас попытаюсь исправиться:
%Как можно видеть передача параметра ByRef, заносит в регистр ecx (в данном случае) реальное значение...
------------------------------------------
Суть в чем, п++ри использовании ByRef передается адрес, чтобы работать с реальным значением, нужно взять его по этому переданному в функцию адресу. Для этого VB сделал mov eсx, [eax], можно было бы записать mov eax, [eax], но это не суть важно...
Я к тому, что, при передаче по ссылке, делается одна лишняя, по сравнению с передачей по значению, операция... вот и все...
Номер ответа: 6
Автор ответа: digitron
Вопросов: 2
Ответов: 23
Профиль | | #6
Добавлено: 29.05.04 21:12
To RomMario:
так VarPtr(i) - тебе возвращает-же ЗНАЧЕНИЕ адреса!
вот ты и передаёшь значение адреса через ByVal.
т.е. в примере вызова API функции:
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef pDst As Any, ByRef pSrc As Any, ByVal ByteLen As Long)
CopyMemory a, b, 4& = БУДЕТ РАВНО = CopyMemory a, ByVal VarPtr(b), 4&
,так как функция принимает значение по ссылке (ByRef), инными словами значение "адреса"
Номер ответа: 7
Автор ответа: LamerOnLine
ICQ: 334781088
Вопросов: 108
Ответов: 2822
Профиль | | #7
Добавлено: 31.05.04 09:03
Многие API функции требуют указатель на какую либо структуру в памяти, но в декларации указыается ByVal, то есть передача по значению.
VarPtr возвращает адрес этой структуры. Его ты и передаешь ПО ЗНАЧЕНИЮ.
Это не совсем логично, но, к сожалению, API функции не пишутся под VB. Это особенно актуально, когда ссылка на переменную или объект находится в структуре. Тут ByRef неприменим.
Номер ответа: 8
Автор ответа: digitron
Вопросов: 2
Ответов: 23
Профиль | | #8
Добавлено: 31.05.04 18:39
Номер ответа: 9
Автор ответа: RomMario
Вопросов: 12
Ответов: 20
Профиль | | #9
Добавлено: 01.06.04 10:42
Номер ответа: 10
Автор ответа: sne
Разработчик Offline Client
ICQ: 233286456
Вопросов: 34
Ответов: 5445
Web-сайт:
Профиль | | #10
Добавлено: 01.06.04 17:21
Ну строку, Double, Single, Variant оно ясно что по ссылке будет быстрее
А вот с Long - остается только гадать, почему такая несправведливость...
Номер ответа: 11
Автор ответа: @CyRax PTR
ICQ: 204447456
Вопросов: 28
Ответов: 664
Web-сайт:
Профиль | | #11
Добавлено: 01.06.04 21:12
2 sne,
Отличный пример. Только нужно было с коментариями.
ByVal:
------
mov eax, [esp+4] 'Переслать в аккумулятор(EAX) число, находящееся по адресу: вершина стёка(ESP) - 4 байта (или извлечь из него верхние 32 бита).
add eax, 1 'Увеличить аккумулятор на 1
===
ByRef:
------
mov eax, [esp+4] 'Переслать в аккумулятор(EAX) число, находящееся по адресу: вершина стёка(ESP) - 4 байта (или извлечь из него верхние 32 бита).
mov ecx, [eax] 'Переслать в счётчик(ECX) число, находящееся по адресу, указанному в аккумуляторе.
add ecx, 1 'Увеличить счётчик на 1
Номер ответа: 12
Автор ответа: digitron
Вопросов: 2
Ответов: 23
Профиль | | #12
Добавлено: 02.06.04 14:13
Номер ответа: 13
Автор ответа: Sharp
Лидер форума
ICQ: 216865379
Вопросов: 106
Ответов: 9979
Web-сайт:
Профиль | | #13
Добавлено: 05.06.04 12:39
> Sharp, ты наверное меня несколько не понял, или я неясно выразился
Я так и подумал
CyRax написал, что происходит. Хотя меня немного удивила такая оптимизация