Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Странное поведение конструкции with ... do [D6, Win2k]


Толик ©   (2002-10-02 15:33:00) 

Столкнулся с такой проблемой:
Есть некая структура: не важно какая, например:

TMyStruct = record
Field1: longint;
Field2: byte;
end;

Далее, я хочу как-то инициализировать переменную, типа TMyStruct с использованием конструкции with. Эта переменная передаётся в ф-ю как var-параметр:

procedure Init(var MyStruct: TMyStruct);
begin
with(MyStruct)do begin
Field1 := 1;
Field2 := 2;
end;
end;

вылезает ошибка "Left side cannot be assigned to" хотя если убрать скобки, то всё работает.

procedure Init(var MyStruct: TMyStruct);
begin
with MyStruct do begin
Field1 := 1;
Field2 := 2;
end;
end;

А вот если объявить TMyStruct не как record, а как class, то работают оба примера. Если передавать MyStruct не по ссылке, а через указатель - тоже всё работает. Если обращатся к MyStruct как к глобальной переменно - тоже работает. А вот с var проблема. На это можно было бы и забить, если бы не ф-я TWinControl.CreateParams(var Params: TCreateParams). Как сие понимать? Это что баг Делфей???


Толик   (2002-10-02 18:03:00) [1]

Огромное спасибо всем принявшим участие в обсуждении!
Если не возражаете, то продолжим завтра. У меня есть ещё пара вопросов по поводу обсуждаемой темы, а сейчас уже домой пора :)


Digitman   (2002-10-02 17:42:00) [2]

Скажу более - и в случае

function CreateProcess(... const lpStartupInfo: TStartupInfo; ...);

параметр будет передан по ссылке (но результат - сам понимаешь, какой будет)


Digitman   (2002-10-02 17:38:00) [3]

>Толик

Смутившие тебя конструкции

function CreateProcess(... constlpStartupInfo: TStartupInfo; ...); stdcall;
и
function CreateProcess(... lpStartupInfo: PStartupInfo; ...); stdcall

будут скомпилированы одинаково, и фактический параметр передан по ссылке в обоих случаях. Обрати внимание на префикс constи соглашение о вызове stdcall.

Вот если бы вызов был декларирован так
function CreateProcess(... lpStartupInfo: TStartupInfo; ...);
компилятор поступил бы иначе : передал бы факт.параметр по значению, "натолкав" значения полей структуры в стек непосредственно перед вызовом.


qube   (2002-10-02 17:23:00) [4]

Init(var MyStruct: TMyStruct) -- неявно передается адрес, где расположены поля структуры

Init(MyObj: TMyClass) -- неявно передается адрес, где расположен экземпляр объекта.

Init(var MyObj: TMyClass) -- неявно передается адрес, где расположен указательна экземпляр объекта.


Игорь Шевченко   (2002-10-02 17:21:00) [5]

>Получается, что и record передаётся по указателю!

Все, что описано как var, гарантировано передается по указателю.
Все, что больше 8-х байт, гарантировано передается по указателю.


Толик   (2002-10-02 17:09:00) [6]

to qube © (02.10.02 16:39)
Допустим, если TMyStruct объявлен как класс, то в ф-ю
Init(var MyStruct: TMyStruct)по ссылке передаётся указатель на экземпляр. Если TMyStruct объявлен как record, то по ссылке передаётся сам экземпляр. Но как тогда объяснить такой факт: есть куча WinAPI"шных ф-й, параметрами которых являются указателина структуру (так написано в хелпе и так работает в C++) Почему же тогда в Делфях надо передавать туда не Адрес объекта типа record, а сам этот объект??? Например:

function CreateProcess(... lpStartupInfo: TStartupInfo; ...);

но не

function CreateProcess(... lpStartupInfo: PStartupInfo; ...);
где
PStartupInfo = :TStartupInfo;

хотя на самлм деле передаётся туда адрес переменной а не переменная
Получается, что и record передаётся по указателю!


McSimm   (2002-10-02 16:53:00) [7]

>почему всё то же самое работает для классов?
Если результатом некоторого выражения является ссылка на экземпляр класса, мы вполне можем обращаться к членам этого класса:

(SomeClassVar).SomeField :=

Однако, обсуждаемая проблема может быть продемонстрирована таким примером:
SomeClassVar := TSomeClassVar.Create - нормально
(SomeClassVar) := TSomeClassVar.Create - ошибка


qube   (2002-10-02 16:39:00) [8]

Для классов работает, потому что экземпляры классов по указателю передаются


Толик   (2002-10-02 16:36:00) [9]

Насчёт того, есть ли смысл подобное выражение брать в скобки - это просто привычка.

По логике вещей, если (MyStruct) действительно выражение (константное), то почему всё то же самое работает для классов?
Если объявить TMyStruct не record, а class, то оба примера компилируются без ошибок.


Best Before 2024   (2002-10-02 16:09:00) [10]

Вот более явный пример:

procedure MyXProc(var X : Integer);
begin
X := X + 1;
end;

procedure MyYProc;
var Y : Integer;
begin
Y := 0;
MyXProc(Y); //Ok
MyXProc((Y)); //[Error]: Constant object cannot be passed
// as var parameter
end;


AlexT1000   (2002-10-02 16:05:00) [11]

with(MyStruct)do begin - а зачем это в скобки брать? смысл?




McSimm   (2002-10-02 16:04:00) [12]

На первый взгляд такое поведение действительно кажется странным.

Однако объяснить это можно.

Дело в том, что для компилятора
MyStruct
и
(MyStruct)
разные вещи. Первое это переменная, второе - выражение, результатом которого является значение типа TMyStruct.


Digitman   (2002-10-02 16:01:00) [13]

Может, и баг.

Ясно одно - компилятор ожидает явное приведение типа:

with TSomeOtherStruc(MyStruct)do begin
Field1 := 1;
Field2 := 2;
end;


Наверх

Титульная страница Поиск, карта сайта Написать письмо