Visual Basic, .NET, ASP, VBScript
 

   
   
     

Форум - Общий форум

Страница: 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-сайт: hw.t-k.ru
 Профиль | | #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-сайт: sharpc.livejournal.com
 Профиль | | #3
Добавлено: 29.05.04 16:09
> заносит в регистр ecx (в данном случае) ссылку на реальное значение...
Ты уверен? Обычно ведь при передаче по ссылке в стек кладется 4-байтовый адрес структуры или Unicode-строки или числа в памяти, а при передаче по значению само число кладется в стек, либо 4-байтовый адрес строки, скопированной как ASCIIZ... Сомневаюсь, что ByRef передает адрес через ECX, ведь API их вполне нормально принимают...

Ответить

Номер ответа: 4
Автор ответа:
 sne



Разработчик Offline Client

ICQ: 233286456 

Вопросов: 34
Ответов: 5445
 Web-сайт: hw.t-k.ru
 Профиль | | #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-сайт: hw.t-k.ru
 Профиль | | #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

To sne:

>>Это я к тому, что если есть возможность, то желательно использовать ByVal...

посмотри:  http://www.mvps.org/vb/hardcore/html/anatomyofbasicprocedurecall.htm

Ответить

Номер ответа: 9
Автор ответа:
 RomMario



Вопросов: 12
Ответов: 20
 Профиль | | #9 Добавлено: 01.06.04 10:42

Всем спасибо. Особенно digitin.

Ответить

Номер ответа: 10
Автор ответа:
 sne



Разработчик Offline Client

ICQ: 233286456 

Вопросов: 34
Ответов: 5445
 Web-сайт: hw.t-k.ru
 Профиль | | #10
Добавлено: 01.06.04 17:21
:) Ну строку, Double, Single, Variant оно ясно что по ссылке будет быстрее :) А вот с Long - остается только гадать, почему такая несправведливость...

Ответить

Номер ответа: 11
Автор ответа:
 @CyRax PTR



ICQ: 204447456 

Вопросов: 28
Ответов: 664
 Web-сайт: basicproduction.nm.ru/
 Профиль | | #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

To sne:

Ну ты понимаешь, что это на обратный вывод наталкивает?

"Пользуйте по возможности ByRef, так как для чисел - это не важно, а для String, и Variant это играет огромную роль"

Ответить

Номер ответа: 13
Автор ответа:
 Sharp


Лидер форума

ICQ: 216865379 

Вопросов: 106
Ответов: 9979
 Web-сайт: sharpc.livejournal.com
 Профиль | | #13
Добавлено: 05.06.04 12:39
> Sharp, ты наверное меня несколько не понял, или я неясно выразился ;)
Я так и подумал :)
CyRax написал, что происходит. Хотя меня немного удивила такая оптимизация :)

Ответить

Страница: 1 |

Поиск по форуму



© Copyright 2002-2011 VBNet.RU | Пишите нам