Консультация № 155447
23.12.2008, 06:57
0.00 руб.
0 8 1
Здравствуйте!
Хочу понять следующий момент.
Из процедуры, назовем ее f1, вызывается подпрограмма f2.
Из f2, в зависимости от условия вызывается либо f3, либо f4.
Но это условие (предположим, оно громоздкое) определяется в f1.

Как можно в процедуру f2 (из f1) передать адрес на f3 или f4, и затем выполнить ту или другую.

Конечно, для начинающих напрашивается простое решение с передачей некоторой булевской переменной, и в зависимости от нее происходит вызов либо f3, либо f4.
Хотелось бы научиться программировать более профессионально с передачей адресов. Собственно, я предполагаю, как получить адрес через @. Но никак не соображу, как потом вызвать процедуру по адресу, ведь обычно чтобы вызвать - пишем ее имя.

Обсуждение

давно
Мастер-Эксперт
425
4118
23.12.2008, 07:11
общий
Бартосик Феликс Михайлович
Конечно, для начинающих напрашивается простое решение с передачей некоторой булевской переменной, и в зависимости от нее происходит вызов либо f3, либо f4. Хотелось бы научиться программировать более профессионально с передачей адресов.

Вот как раз то, что Вы хотите, побаловаться с адресами если можно обойтись одной логической переменной, и есть непрофессиональное программирование.
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
23.12.2008, 07:40
общий
Не совсем с Вами согласен sir Henry.
Предполагал, что ситуация, которую опишу ниже, очевидна.

Допустим вызов f3 (либо f4) происходит в цикле, а у меня стоит задача оптимизировать код, т.е. "облизываем" каждую инструкцию для большей скорости работы программы.
И одно дело, если в цикле идет вызов подпрограммы по конкретному адресу, и другое дело, если в цикле стоит еще условие проверки булевской переменной.

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

1 вариант)
f2 proc
цикл..........
if <одно>
call <адрес1>
else ;<другое>
call <адрес2>
endif
............
f2 endp

2 вариант)
f1 proc
..........
mov <адрес_X>, <либо адрес f3,либо адрес f4>
............
f1 endp

f2 proc
цикл..........
call <адрес_X>
............
f2 endp
давно
Мастер-Эксперт
425
4118
23.12.2008, 08:17
общий
Бартосик Феликс Михайлович
Предполагал, что ситуация, которую опишу ниже, очевидна.

Ниже то она может и очевидна, но чтобы не согласиться со мной, Вам нужно было это изложить в вопросе.
Давайте тогда определимся с задачей:
1. Вам нужно максимально оптимизировать код по времени выполнения.
2. Или всё же Вы хотите писать программу на языке программирования высокого уровня с целью написать программу быстро.
Я, конечно, понимаю, что можно с целью увеличения скорости сделать те или иные варианты кода высокого уровня, однако по сравнению с чистым ассемблером эти варианты не будут иметь решающего значения, т.к. компилятор Дельфи всё равно затолкает в бинарник столько всякой чепухи, что мама не горюй.
Если всё таки нужно совместить скорость написания интерфейса программы с пользователем со скоростью выполнения отдельных участков кода, то эти критичные по скорости участки лучше всего оформить в виде самостоятельных ассемблерных процедур, где Вы сами вставите только тот код, который нужен для выполнения задачи ибо, опять же повторюсь, код на Дельфи натолкает Вам туда чёрте что и сбоку бантик.
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
23.12.2008, 10:46
общий
Спасибо насчет ассемблерных вставок,
просто я думал, что в данной ситуации можно обойтись одним паскалем.
Ну хотя бы подскажите мне :
как можно объявить переменную типа - "указатель на процедуру".
^Real я знаю, а здесь как?
^Procedure?
Неизвестный
23.12.2008, 10:57
общий
это ответ
Здравствуйте, Бартосик Феликс Михайлович!

Если у вас процедуры с одинаковым списком параметров (а так оно обычно и бывает), то описываете процедурный тип, например, TMyProc = procedure(A : Integer); а свою f2 как procedure f2(MyProc : TMyProc). В f1 вызывавем f2(f3) либо f2(f4). А внутри f2 - используем просто в лоб MyProc(a).

P.S. После прочтения вашей дискуссии в минифоруме полагаю это именно то, что вы спрашивали. В плюсах такого подхода (по сравнению с передачей просто указателей - хотя могу и такой "непрофессиональный" или "суперпрофессиональный"вариант описать - иногда приходится делать) еще и то, что компилятор проверит типы процедур на соответствие - что оградит от "глупых" ошибок.
давно
Мастер-Эксперт
425
4118
23.12.2008, 11:22
общий
В принципе обойтись можно и Паскалем. Только не зная требований к скорости выполнения...
Вот смотрите. Вам в любом случае надо проверять условие чтобы знать, какую процедцрц вызвать - f3 или f4. Вы согласны?
Не факт, что f3\f4 нужно вызывать непременно из f2, можно ведь вызвать и из f1, раз решение о выборе процедуры принимается именно там.
Даже если процедуру f2 не обойти и не объехать на кривой козе, можно сделать, например, так:
Код:
Procedure f1;
Begin
...
If (Проверяем условие выбора f3\f4) Then
Begin
f2;
f3;
End
Else
Begin
f2;
f4;
End;
...
End;

Скорость, при этом, нисколько не страдает. Ну разве что совсем чуть-чуть...
------------------
Процедурные типы можно объявить, например, так:
Код:
Type
//Объявляем шаблон функции. f3 и f4 должны иметь такие же параметры
TMyFunc = Function(var1: Integer; var2: String): Boolean;

Var
MyFunc: TMyFunc;

Begin
...
If ((Проверяем условие выбора f3\f4) Then
MyFunc:=f3
Else
MyFunc:=f4;
End;

Поскольку здесь присваивание идёт переменной типа Функция, то ей присваивается не результат, а адрес соответствующей функции.
Об авторе:
Я только в одном глубоко убеждён - не надо иметь убеждений! :)
Неизвестный
24.12.2008, 06:23
общий
Спасибо всем за помощь в объявлении процедурных типов!
Неизвестный
24.12.2008, 12:10
общий
Еще раз извините, может кому будет интересен следующий код.
Мне почему то сразу не пришло в голову сохранять адрес в глобальной переменной
Код:

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
procedure f3;
procedure f4;
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1; b:Pointer;

implementation

{$R *.dfm}
procedure f2;
begin
//........... здесь какой-то код
asm
call b
end
//........... здесь какой-то код
end;

procedure Tform1.f3;
begin
Edit1.text:='3'
end;

procedure Tform1.f4;
begin
Edit1.text:='4'
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
b:=@Tform1.f3;
f2;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
b:=@Tform1.f4;
f2;
end;

end.



Ну а передаваемые переменные тоже можно сохранять глобально -
f3, или f4 сами возьмут свое.
Все может быть и криво, но так можно вызывать, если f3, или f4 имеют разные входные параметры
Форма ответа