Сегодня на лекции меня спросили про реализацию передачи параметров "по CONST" в Delphi. Я как-то оказался неготов к ответу, сказалось многолетнее отсутствие программистской практики, и я понес какую-то чушь. Сейчас, играя на бильярде, я внезапно вспомнил правильные слова и, бросив кий, пишу этот пост.
Технически параметры, около которых стоит CONST, передаются точно так же, как и те, у которых стоит VAR. Т.е. в обоих этих случаях используется совершенно одинаковый способ передачи параметров "по ссылке" - на верхушку стека выкладывается указатель на переменную, которая передается в качестве параметра.
Зачем же тогда нужно специальное ключевое слово, если CONST = VAR? Просто если написать VAR, то есть риск случайно поменять значение переменной внутри функции. А если не написать VAR, то передача производится по значению (переменная копируется), что может быть накладно для больших переменных типа паскалевских строк или массивов. Поэтому в Delphi реализован промежуточный вариант: VAR + дополнительный контроль компилятором того, что данный параметр нигде не встречается в левой части оператора присвоения.
Таким образом, с точки зрения реализации есть два способа передачи параметров посредством стека - по значению и по ссылке. Остальное - вариации.

А я думал в чем разница между наличием const и его отсутствием. С var то было понятно всегда.
ОтветитьУдалитьСпасибо.
Сейчас обсуждал это дело с Романом (знающие поймут), у них в отделе был спор по этому поводу: "Как передается параметр по const" если говорить про Delphi, то есть мнение что там передается по значению или по ссылке в зависимости от размера данных, например boolean как выяснилось в том споре - передается по значению. (Это проверили дизасемблировав программу). Может у кого есть достоверно известные данные как ведет себя Delphi при компиляции подобных выражений ???
ОтветитьУдалитьОфициально: параметры с модификатором const передаются по ссылке, если их размер больше размера указателя. В противном случае, они передаются по значению. http://www2.toki.or.id/fpcdoc/ref/refsu39.html#x92-980008.3
ОтветитьУдалитьhttp://www.gnu-pascal.de/gpc/Subroutine-Parameter-List-Declaration.html#Subroutine-Parameter-List-Declaration
Однако, если я правильно понял, менять такой параметр все равно запрещено.
Мы тоже так подумалиб и в самом деле каков смысл передавать указатель на значение которое меньше чем собственно сам указатель (опять же пример с булей - оно же 1 байт), вот только уверенности не было. Миша - респект! Ты как всегда точен! ;)
ОтветитьУдалитьЭта "стройная картина мира" неверна! Хотя сам до недавнего времени считал так же, как и автор:
ОтветитьУдалитьprocedure Foo(
p1 : PChar;
var p2 : PChar;
p3 : PChar;
const p4 : PChar);
Дизассемблирование в отладчике Дельфи покажет, что const передастся по значению, и только var - будет отличаться от всех остальных.
Вот почему фирменные StrCat и StrCopy например, вторым параметром имеют const Source: PChar, что было-бы глупо (масло-масленное) с точки зрения той картины, которую описал автор.
Из этого, кстати, следует ещё один важный вывод - что для передачи параметром Объекта, модификатор const вообще бесполезен (ничего не даёт, так как даже при нем модификация полей разрешается, а сам параметр и так передается в обоих случаях по значению) и поэтому Sender всегда идет в исходниках "чистый" - без const.
Без модификатора Const возможно изменение переданного параметра (ссылки на объект) внутри метода, что может вести к ошибкам, т.к. программист может ошибочно предполагать, что переданная ссылка или параметр неизменяемый:
Удалитьprocedure TForm4.Test(AObject: TObject);
begin
AObject := ... ; // зачем, непонятно,
// но об этом через страницу тела метода забыли
AObject.foo() // и обратились уже к другому экземпляру, например. Или еще хуже, если выше AObject := nil (только не спрашивайте, зачем, я и не такое видел)
end;