Форум: "Начинающим";
Текущий архив: 2008.03.30;
Скачать: [xml.tar.bz2];
Внизconst в параметрах Найти похожие ветки
← →
махс (2008-03-02 11:23) [0]Загадка для меня. В каких случаях в процедуру или функцию передают значение константой;
Я понимаю, что это означает. Но вот когда именно это применяют не пойму. Бывает выжу чужой исходник, в функцию передают пять параметров - не один внутри функции не изменяют, а с констнтой идет только самый первый.
Поясните?
Спасибо.
← →
Anatoly Podgoretsky © (2008-03-02 11:30) [1]> махс (02.03.2008 11:23:00) [0]
А пример?
← →
махс (2008-03-02 13:08) [2]Ну вот пример из боландовских исходников:
function StrToIntDef(const S: string; Default: Integer): Integer;
var
E: Integer;
begin
Val(S, Result, E);
if E <> 0 then Result := Default;
end;
Почему бы тут не передать Default, как const?
← →
{RASkov} © (2008-03-02 13:23) [3]> Почему бы тут не передать Default, как const?
Ну "забыли" борландовцы....
> Загадка для меня. В каких случаях в процедуру или функцию
> передают значение константой;
Тыж говоришь:
> Я понимаю, что это означает.
Откуда тогда такие вопросы?
Значит ты не понимаешь :(
В данном случае не смотри на чужой код с поспешными выводами, а разберись досканально - что и для чего...
← →
Игорь Шевченко © (2008-03-02 13:33) [4]
>
> Почему бы тут не передать Default, как const?
Потому что для Integer без разницы, как его передавать, а для string разница есть. А раз без разницы, зачем лишние буквы набивать.
← →
Anatoly Podgoretsky © (2008-03-02 13:34) [5]
> Бывает выжу чужой исходник, в функцию передают пять параметров
Где пять параметров.
А в приведеном коде без разницы, что const, что без.
Приводи примет, а то беспредметный разговор.
← →
{RASkov} © (2008-03-02 14:20) [6]> Потому что для Integer без разницы, как его передавать
Что-то я в замешательстве....procedure M(const I: Integer);
иprocedure M1(I: Integer);
одинаковые что ли?
т.е. вызов М1 не "раздвоит" значение?? Что-то здесь не так..... а ведь "раздвоит", так как:N:=5;
M1(N);
ShowMessage(IntTostr(N));
при:procedure M1(I: Integer);
begin
....
I:=Random(I);
end;
Покажет(должно показать) - 5...
или я не верно понял [4],[5] :( ...т.е. не в контексте вопроса автора, а в целом.
Я так считал, что:
1 -function StrToIntDef(const S: string; Default: Integer): Integer;
2 -function StrToIntDef(const S: string; const Default: Integer): Integer;
вторая функция будет работать "быстрее" первой.... ибо не будет копироваться значение, а передастся ссылка....
← →
Anatoly Podgoretsky © (2008-03-02 14:28) [7]> {RASkov} (02.03.2008 14:20:06) [6]
Ссылки для интегер работают медленнее значений.
← →
{RASkov} © (2008-03-02 14:29) [8]Почему появилось [6].
Я пробегся по нескольким местам в VCL и нигде не встретил (const xx: Integer) или (const xx: Cardinal).....
Var - были, а конст нигде.... только по значению..... Странно все это :)
В прочем я не так и много мест просмотрел....
← →
{RASkov} © (2008-03-02 14:30) [9]> [7] Anatoly Podgoretsky © (02.03.08 14:28)
Ясно.... спасибо)
← →
Игорь Шевченко © (2008-03-02 14:35) [10]
> procedure M(const I: Integer);
> и
> procedure M1(I: Integer);
> одинаковые что ли?
С точки зрения передачи параметров, быстродействия и прочих аспектов времени выполнения абсолютно одинаковые.
С точки зрения компиляции компилятор будет ругаться, если внутри процедуры параметру будет что-то присваиваться.
Давно бы откомпилировал и посмотрел
← →
{RASkov} © (2008-03-02 14:49) [11]> [10] Игорь Шевченко © (02.03.08 14:35)
> Давно бы откомпилировал и посмотрел
Мне известно что будет с "const" и без нее...
Я именно про саму передачу параметра.... с const(var) - у нас одна "переменная", без - две. (утрировано)
> С точки зрения передачи параметров, быстродействия и прочих
> аспектов времени выполнения абсолютно одинаковые.
Что-то опять не то.... См [7] :(
> С точки зрения компиляции компилятор....
Ну его точка зрения мне понятна...:)
← →
Anatoly Podgoretsky © (2008-03-02 14:53) [12]
> Что-то опять не то.... См [7] :(
Не путай передачу по значению, с передачей по ссылке.
И смотри окно CPU что бы определить как передается интегер при const, var и без модификатора.
← →
Игорь Шевченко © (2008-03-02 15:12) [13]{RASkov} © (02.03.08 14:49) [11]
> > С точки зрения передачи параметров, быстродействия и прочих
>
> > аспектов времени выполнения абсолютно одинаковые.
>
> Что-то опять не то.... См [7] :(
А что смотреть на 7 ? Лучше смотреть на грамматику языка. В которой сказано, что параметры передаются по значению, если не указано слово var.
← →
{RASkov} © (2008-03-02 15:50) [14]> [12] Anatoly Podgoretsky © (02.03.08 14:53)
> Не путай передачу по значению, с передачей по ссылке.
А где я что напутал?
> И смотри окно CPU
А вот туда я не умею смотреть, т.е. смотреть-то туда умею, но там ничего не понимаю :(
> [13] Игорь Шевченко © (02.03.08 15:12)
> В которой сказано, что параметры передаются по значению,
> если не указано слово var
или const... еще out ...
>
Ладно.... фик с ними :) Что-то мы тут запутались..... т.е. я запутался и вас путаю... )
← →
oxffff © (2008-03-02 16:10) [15]
> махс (02.03.08 13:08) [2]
> Ну вот пример из боландовских исходников:
>
> function StrToIntDef(const S: string; Default: Integer):
> Integer;
В данном случае при const имеет смысл для S, по скольку S является managed типом (не в терминах .NET естествено), const означает, что локальная переменая является синонимом
(это подавляет вызовы addref/release при assign op, и finalize при scope exit )
переданного параметра с ораниченным временем жизни
Однако оные выкрутасы могут приводить к проблемам, например вот одна из них выдуманная на ходу
var GlobalA:string;
implementation
{$R *.dfm}
procedure HarmfulProc(const a:string);
var b:string;
begin
GlobalA:=""; //Освобождает память
b:=a; //Копируем invalid ref //
end; //Освобождает память снова //AV
procedure TForm1.Button1Click(Sender: TObject);
begin
GlobalA:="SomeText";
GlobalA:=GlobalA+GlobalA;
HarmfulProc(GlobalA);
end;
← →
oxffff © (2008-03-02 16:12) [16]
> (это подавляет вызовы addref/release при assign op, и finalize
> при scope exit )
Подавляет вызов addref при передачи параметра.
← →
{RASkov} © (2008-03-02 16:19) [17]> [15] oxffff © (02.03.08 16:10)
> Однако оные выкрутасы могут приводить к проблемам, например
> вот одна из них выдуманная на ходу
Помоему это нужно специально так придумать, да и не каждому дано так придумать :) я про код)
← →
oxffff © (2008-03-02 16:24) [18]
> {RASkov} © (02.03.08 16:19) [17]
Пример надуман, однако такая ситуация имеет место быть.
Такая ситуация может неявно возникнуть в многопоточном приложении.
← →
Loginov Dmitry © (2008-03-02 19:05) [19]> Почему бы тут не передать Default, как const?
1) это ничего не даст. Просто нельзя будет изменять значение переменной в процедуре, вот и все.
2) const и var при передаче глобальных переменных является потенциальной проблемой в многопоточном приложении.
А переменные String передавать с Const - это скорее правило хорошего тона. Именно в примере [2] оптимизации от этого никакой нет, т.к. нет обращения к отдельным символам строки. В других же случаях наличие Const может заметно улучшить производительность приложения по сравнению с его отсутствием.
← →
oxffff © (2008-03-02 19:30) [20]
> Loginov Dmitry © (02.03.08 19:05) [19]
Разница есть.
procedure abc(s:string);
begin
end;
procedure abcEx(const s:string);
begin
end;
procedure TForm1.Button1Click(Sender: TObject);
var i:Integer;
Tick1,Tick2:DWORD;
begin
Tick1:=GetTickCount;
for i:=0 to 100000000 do abc("123");
Tick1:=GetTickCount-Tick1;
Tick2:=GetTickCount;
for i:=0 to 100000000 do abcEx("123");
Tick2:=GetTickCount-Tick2;
showmessage(inttostr(Tick1)+" "+inttostr(Tick2));
end;
← →
oxffff © (2008-03-02 19:39) [21]
> Loginov Dmitry © (02.03.08 19:05) [19]
> > Почему бы тут не передать Default, как const?
>
>
> 1) это ничего не даст. Просто нельзя будет изменять значение
> переменной в процедуре, вот и все.
Опять заблуждение, хочешь пример?
TypeA=record
A,B,C,D:integer;
end;
procedure abc(s:TypeA);
begin
end;
procedure abcEx(const s:TypeA);
begin
end;
procedure TForm1.Button1Click(Sender: TObject);
var i:Integer;
Tick1,Tick2:DWORD;
A:TypeA;
begin
Tick1:=GetTickCount;
for i:=0 to 1000000000 do abc(A);
Tick1:=GetTickCount-Tick1;
Tick2:=GetTickCount;
for i:=0 to 1000000000 do abcEx(A);
Tick2:=GetTickCount-Tick2;
showmessage(inttostr(Tick1)+" "+inttostr(Tick2));
end;
Учти пример еще без Managed типов.
← →
{RASkov} © (2008-03-02 19:48) [22]Дайте поймаю мысль...
> Разница есть.
С таким кодом:
procedure abc(i: integer);
begin
//по значению
end;
procedure abcEx(const i: integer);
begin
//по ссылки
end;
procedure TForm1.Button1Click(Sender: TObject);
var i:Integer;
Tick1,Tick2:DWORD;
begin
Tick1:=GetTickCount;
for i:=0 to 100000000 do abc(5);
Tick1:=GetTickCount-Tick1;
Tick2:=GetTickCount;
for i:=0 to 100000000 do abcEx(5);
Tick2:=GetTickCount-Tick2;
showmessage(inttostr(Tick1)+" "+inttostr(Tick2));
end;
Тоже есть.... в 3 раза... с конст итегер быстрее.... как же понять [7]?
← →
oxffff © (2008-03-02 20:05) [23]
> procedure abcEx(const i: integer);
> begin
> //по ссылки
> end;
Увы. Это не по ссылке. см. Delphi help
← →
oxffff © (2008-03-02 20:09) [24]
> как же понять [7]?
procedure abc(i: integer);
begin
end;
procedure abcEx(const i: integer);
begin
end;
Этот код исполняется идентично.
← →
{RASkov} © (2008-03-02 20:16) [25]> [24] oxffff © (02.03.08 20:09)
> Этот код исполняется идентично.
Как же идентично, а по времени выполнения - поразному?
← →
oxffff © (2008-03-02 20:37) [26]
> {RASkov} © (02.03.08 20:16) [25]
Поменяй вызов.
цикл abc(5);
цикл abcEx(5);
цикл abcEx(5);
цикл abc(5);
← →
oxffff © (2008-03-02 20:38) [27]У меня
Вариант 1
1094 abc
1141 abcEX
Вариант 2
1094 abcEX
1140 abc
← →
{RASkov} © (2008-03-02 20:46) [28]> [27] oxffff © (02.03.08 20:38)
Ну фик знает)
procedure abc(i: integer);
begin
//ii cia?aie?
end;
procedure abcEx(const i: integer);
begin
//ii nnueee
end;
procedure TForm1.Button1Click(Sender: TObject);
var i:Integer;
Tick1,Tick2:DWORD;
begin
Tick1:=GetTickCount;
for i:=0 to 100000000 do abc(555);
Tick1:=GetTickCount-Tick1;
Tick2:=GetTickCount;
for i:=0 to 100000000 do abcEx(555);
Tick2:=GetTickCount-Tick2;
showmessage(inttostr(Tick1)+" - "+inttostr(Tick2));
end;
procedure TForm1.Button2Click(Sender: TObject);
var i:Integer;
Tick1,Tick2:DWORD;
begin
Tick1:=GetTickCount;
for i:=0 to 100000000 do abcEx(555);
Tick1:=GetTickCount-Tick1;
Tick2:=GetTickCount;
for i:=0 to 100000000 do abc(555);
Tick2:=GetTickCount-Tick2;
showmessage(inttostr(Tick1)+" - "+inttostr(Tick2));
end;
---------------------------
Button1Click
922 - 297
---------------------------
Button2Click
485 - 906
---------------------------
← →
oxffff © (2008-03-02 20:49) [29]
> RASkov} © (02.03.08 20:46) [28]
Попробуй именно в одной процедуре.
Один раз запустил зафиксировал.
Поменял, запустил, зафиксировал.
← →
{RASkov} © (2008-03-02 21:03) [30]---------------------------
Project1
---------------------------
(abcEx)266 - (abc)906
---------------------------
OK
---------------------------
---------------------------
Project1
---------------------------
(abc)860 - (abcEx)312
---------------------------
OK
---------------------------
?? :) Я уже по всякому перепробывал и все равно с конст быстрее....
вот еще результаты:
--begin test1--
abc - 907, abcEx 312
abc - 906, abcEx 313
abc - 907, abcEx 312
abc - 922, abcEx 297
abc - 922, abcEx 297
--end test1 begin test2--
abc - 250, abcEx 875
abc - 266, abcEx 859
abc - 250, abcEx 875
abc - 266, abcEx 859
abc - 250, abcEx 875
--end test2--
← →
{RASkov} © (2008-03-02 21:07) [31]Вот целиком модуль
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure abc(i: integer);
begin
//ii cia?aie?
end;
procedure abcEx(const i: integer);
begin
//ii nnueee
end;
procedure Test1;
var i:Integer;
Tick1,Tick2:DWORD;
begin
Tick1:=GetTickCount;
for i:=0 to 100000000 do abc(555);
Tick1:=GetTickCount-Tick1;
Tick2:=GetTickCount;
for i:=0 to 100000000 do abcEx(555);
Tick2:=GetTickCount-Tick2;
Form1.Memo1.Lines.Add(Format("abc - %3d, abcEx %3d", [Tick1, Tick2]));
end;
procedure Test2;
var i:Integer;
Tick1,Tick2:DWORD;
begin
Tick1:=GetTickCount;
for i:=0 to 100000000 do abcEx(555);
Tick1:=GetTickCount-Tick1;
Tick2:=GetTickCount;
for i:=0 to 100000000 do abc(555);
Tick2:=GetTickCount-Tick2;
Form1.Memo1.Lines.Add(Format("abc - %3d, abcEx %3d", [Tick1, Tick2]));
end;
procedure TForm1.Button1Click(Sender: TObject);
var N: Integer;
begin
Form1.Memo1.Lines.Add("--begin test1--");
for N:=0 to 4 do begin Test1; sleep(100); end;
Form1.Memo1.Lines.Add("--end test1 begin test2--");
for N:=0 to 4 do begin Test2; sleep(100); end;
Form1.Memo1.Lines.Add("--end test2--");
end;
procedure TForm1.Button2Click(Sender: TObject);
var i:Integer;
Tick1,Tick2:DWORD;
begin
Tick1:=GetTickCount;
for i:=0 to 100000000 do abc(555);
Tick1:=GetTickCount-Tick1;
Tick2:=GetTickCount;
for i:=0 to 100000000 do abcEx(555);
Tick2:=GetTickCount-Tick2;
showmessage(inttostr(Tick1)+" - "+inttostr(Tick2));
end;
end.
Вообщем нового, как я ни старался, из этой ветки я не узнал :( А так все началось интересно.. :)
← →
Loginov Dmitry © (2008-03-02 21:09) [32]> Опять заблуждение, хочешь пример?
Вообще-то ранее решь шла именно о Default, как параметре целого типа. Никакие TypeA не фигурировали.
Да и в [20] пример некорректный. showmessage там ни о чем не говорит.
← →
Anatoly Podgoretsky © (2008-03-02 21:10) [33]> oxffff (02.03.2008 20:49:29) [29]
Зачем измерять обращение к пустой функции, основные затраты как раз внутри.
← →
Loginov Dmitry © (2008-03-02 21:13) [34]> Зачем измерять обращение к пустой функции, основные затраты
> как раз внутри.
Кстати да, на ассемблере оба участка кода абсолютно одинаковые :)
← →
{RASkov} © (2008-03-02 21:18) [35]> Зачем измерять обращение к пустой функции, основные затраты
> как раз внутри.
Вот другое дело, я что-то сразу и не сообразил
procedure abc(i: integer);
begin
Form1.Tag:=I*Random(I);
end;
procedure abcEx(const i: integer);
begin
Form1.Tag:=I*Random(I);
end;
--begin test1--
abc - 703, abcEx - 687
abc - 687, abcEx - 703
abc - 688, abcEx - 703
abc - 703, abcEx - 687
abc - 687, abcEx - 688
--end test1 begin test2--
abc - 734, abcEx - 688
abc - 735, abcEx - 687
abc - 735, abcEx - 687
abc - 734, abcEx - 703
abc - 734, abcEx - 703
--end test2--
Получается одинаково.... Странно все это :)
← →
oxffff © (2008-03-02 21:25) [36]
> Loginov Dmitry © (02.03.08 21:09) [32]
> > Опять заблуждение, хочешь пример?
>
>
> Вообще-то ранее решь шла именно о Default, как параметре
> целого типа. Никакие TypeA не фигурировали.
>
> Да и в [20] пример некорректный. showmessage там ни о чем
> не говорит.
А ты оптимизатор отключи. И тогда тебе станет все понятно.
← →
oxffff © (2008-03-02 21:27) [37]
> Anatoly Podgoretsky © (02.03.08 21:10) [33]
Отключите оптимизатор, чтобы компилятор не искал зависимости.
← →
Loginov Dmitry © (2008-03-02 21:27) [38]> Получается одинаково.... Странно все это :)
Прикол в том, что компилятор "забил" на директиву const и передал I по значению :)
← →
Anatoly Podgoretsky © (2008-03-02 21:30) [39]> oxffff (02.03.2008 21:27:37) [37]
Зачем, меня эти тесты не интересуют
← →
Loginov Dmitry © (2008-03-02 21:31) [40]> А ты оптимизатор отключи. И тогда тебе станет все понятно.
А ты сам сперва попробуй!
← →
Anatoly Podgoretsky © (2008-03-02 21:31) [41]> Loginov Dmitry (02.03.2008 21:27:38) [38]
С чего ты ставишь знак равенства между ссылка и const - тебе Борланд это обещал?
← →
oxffff © (2008-03-02 21:32) [42]
> Прикол в том, что компилятор "забил" на директиву const
> и передал I по значению :)
Прикол в том, что тебе нужно перечитать Help. :)
Внимательно изучить [20] и [21] c учетом [36]
(либо вынудить оптимизатор не пропускать код).
← →
oxffff © (2008-03-02 21:34) [43]
> Loginov Dmitry © (02.03.08 21:31) [40]
> > А ты оптимизатор отключи. И тогда тебе станет все понятно.
>
>
>
> А ты сам сперва попробуй!
5562 и 484. Догадайся где быстрее.
← →
Loginov Dmitry © (2008-03-02 21:37) [44]> 5562 и 484. Догадайся где быстрее.
Быстрее второй цикл. И что из этого? Const-то тут причем?
← →
oxffff © (2008-03-02 21:37) [45]
> Anatoly Podgoretsky © (02.03.08 21:30) [39]
> > oxffff (02.03.2008 21:27:37) [37]
>
> Зачем, меня эти тесты не интересуют
А как быть с Anatoly Podgoretsky © (02.03.08 14:28) [7]?
Ведь нет разницы, что
procedure abc(i: integer);
begin
..
end;
procedure abcEx(const i: integer);
begin
..
end;
← →
Loginov Dmitry © (2008-03-02 21:38) [46]> Прикол в том, что тебе нужно перечитать Help.
Да без проблем! Где тебе непонятно? Давай почитаю!
:)
← →
oxffff © (2008-03-02 21:39) [47]
> Loginov Dmitry © (02.03.08 21:37) [44]
> > 5562 и 484. Догадайся где быстрее.
>
>
> Быстрее второй цикл. И что из этого? Const-то тут причем?
>
Как причем? Это благодаря const. Ты что не в курсе?
← →
Anatoly Podgoretsky © (2008-03-02 21:40) [48]> oxffff (02.03.2008 21:37:45) [45]
А с чего бы здесь была разница, когда 32 бита передается через регистр eax
← →
{RASkov} © (2008-03-02 21:40) [49]> А как быть с Anatoly Podgoretsky © (02.03.08 14:28) [7]?
>
> Ведь нет разницы, что...
Кстати, да, как?
>
Кому верить...
:о)
← →
oxffff © (2008-03-02 21:41) [50]
> Loginov Dmitry © (02.03.08 21:38) [46]
> > Прикол в том, что тебе нужно перечитать Help.
>
>
> Да без проблем! Где тебе непонятно? Давай почитаю!
> :)
Подожди. Подожди.
Твои слова. Loginov Dmitry © (02.03.08 19:05) [19]
А переменные String передавать с Const - это скорее правило хорошего тона. Именно в примере [2] оптимизации от этого никакой нет, т.к. нет обращения к отдельным символам строки.
Тебе показали, что это не так. Или ты решил съехать? :)
← →
{RASkov} © (2008-03-02 21:42) [51]> [48] Anatoly Podgoretsky © (02.03.08 21:40)
Ясно.... что нифика не ясно :(
> [47] oxffff © (02.03.08 21:39)
> Как причем? Это благодаря const. Ты что не в курсе?
Вот и я так думал.... :(
← →
oxffff © (2008-03-02 21:42) [52]
> {RASkov} © (02.03.08 21:40) [49]
> > А как быть с Anatoly Podgoretsky © (02.03.08 14:28)
> [7]?
> >
> > Ведь нет разницы, что...
>
> Кстати, да, как?
>
> >
> Кому верить...
> :о)
Верить только себе и help Delphi (но лучше отладчику). :)
← →
Loginov Dmitry © (2008-03-02 21:46) [53]> Тебе показали, что это не так.
Неужели? И где это было?
← →
oxffff © (2008-03-02 21:46) [54]
> {RASkov} © (02.03.08 21:42) [51]
> > [48] Anatoly Podgoretsky © (02.03.08 21:40)
>
> Ясно.... что нифика не ясно :(
>
>
> > [47] oxffff © (02.03.08 21:39)
> > Как причем? Это благодаря const. Ты что не в курсе?
>
> Вот и я так думал.... :(
Что ты не понял?
При передачи как
const значений для managed типов. Для них не вызывается Addref/finalize.
разница между передачей "длинного параметра" const и value, что оба по ссылке. Но для value создается копия в стеке в процедуре+затраты на managed типы. А для const нет.
Для не managed "коротких параметров" разницы нет.
см. Help
Parameters are transferred to procedures and functions via CPU registers or the stack, depending on the routine"s calling convention. For information about calling conventions, see Calling conventions.
Variable (var) parameters are always passed by reference, as 32-bit pointers that point to the actual storage location.
Value and constant (const) parameters are passed by value or by reference, depending on the type and size of the parameter:
An ordinal parameter is passed as an 8-bit, 16-bit, 32-bit, or 64-bit value, using the same format as a variable of the corresponding type.
A real parameter is always passed on the stack. A Single parameter occupies 4 bytes, and a Double, Comp, or Currency parameter occupies 8 bytes. A Real48 occupies 8 bytes, with the Real48 value stored in the lower 6 bytes. An Extended occupies 12 bytes, with the Extended value stored in the lower 10 bytes.
A short-string parameter is passed as a 32-bit pointer to a short string.
A long-string or dynamic-array parameter is passed as a 32-bit pointer to the dynamic memory block allocated for the long string. The value nil is passed for an empty long string.
A pointer, class, class-reference, or procedure-pointer parameter is passed as a 32-bit pointer.
A method pointer is passed on the stack as two 32-bit pointers. The instance pointer is pushed before the method pointer so that the method pointer occupies the lowest address.
Under the register and pascal conventions, a variant parameter is passed as a 32-bit pointer to a Variant value.
Sets, records, and static arrays of 1, 2, or 4 bytes are passed as 8-bit, 16-bit, and 32-bit values. Larger sets, records, and static arrays are passed as 32-bit pointers to the value. An exception to this rule is that records are always passed directly on the stack under the cdecl, stdcall, and safecall conventions; the size of a record passed this way is rounded upward to the nearest double-word boundary.
An open-array parameter is passed as two 32-bit values. The first value is a pointer to the array data, and the second value is one less than the number of elements in the array.
When two parameters are passed on the stack, each parameter occupies a multiple of 4 bytes (a whole number of double words). For an 8-bit or 16-bit parameter, even though the parameter occupies only a byte or a word, it is passed as a double word. The contents of the unused parts of the double word are undefined.
Under the pascal, cdecl, stdcall and safecall conventions, all parameters are passed on the stack. Under the pascal convention, parameters are pushed in the order of their declaration (left-to-right), so that the first parameter ends up at the highest address and the last parameter ends up at the lowest address. Under the cdecl, stdcall, and safecall conventions, parameters are pushed in reverse order of declaration (right-to-left), so that the first parameter ends up at the lowest address and the last parameter ends up at the highest address.
Under the register convention, up to three parameters are passed in CPU registers, and the rest (if any) are passed on the stack. The parameters are passed in order of declaration (as with the pascal convention), and the first three parameters that qualify are passed in the EAX, EDX, and ECX registers, in that order. Real, method-pointer, variant, Int64, and structured types) do not qualify as register parameters, but all other parameters do. If more than three parameters qualify as register parameters, the first three are passed in EAX, EDX, and ECX, and the remaining parameters are pushed onto the stack in order of declaration. For example, given the declaration
procedure Test(A: Integer; var B: Char; C: Double; const D: string; E: Pointer);
a call to Test passes A in EAX as a 32-bit integer, B in EDX as a pointer to a Char, and D in ECX as a pointer to a long-string memory block; C and E are pushed onto the stack as two double-words and a 32-bit pointer, in that order.
Register saving conventions
Procedures and functions must preserve the EBX, ESI, EDI, and EBP registers, but can modify the EAX, EDX, and ECX registers. When implementing a constructor or destructor in assembler, be sure to preserve the DL register. Procedures and functions are invoked with the assumption that the CPU"s direction flag is cleared (corresponding to a CLD instruction) and must return with the direction flag cleared.
Note
Delphi language procedures and functions are generally invoked with the assumption that the FPU stack is empty: The compiler tries to use all eight FPU stack entries when it generates code.
When working with the MMX and XMM instructions, be sure to preserve the values of the xmm and mm registers. Delphi functions are invoked with the assumption that the x87 FPU data registers are available for use by x87 floating point instructions. That is, the compiler assumes that the EMMS/FEMMS instruction has been called after MMX operations. Delphi functions do not make any assumptions about the state and content of xmm registers. They do not guarantee that the content of xmm registers is unchanged.
← →
oxffff © (2008-03-02 21:51) [55]
> Loginov Dmitry © (02.03.08 21:46) [53]
> > Тебе показали, что это не так.
>
>
> Неужели? И где это было?
Без оптимизатора попробуй. Чтобы компилятор не пропускал код, если нет зависимости.
procedure abc(s:string);
begin
end;
procedure abcEx(const s:string);
begin
end;
procedure TForm1.Button1Click(Sender: TObject);
var i:Integer;
Tick1,Tick2:DWORD;
begin
Tick1:=GetTickCount;
for i:=0 to 100000000 do abc("123");
Tick1:=GetTickCount-Tick1;
Tick2:=GetTickCount;
for i:=0 to 100000000 do abcEx("123");
Tick2:=GetTickCount-Tick2;
showmessage(inttostr(Tick1)+" "+inttostr(Tick2));
end;
← →
Anatoly Podgoretsky © (2008-03-02 21:52) [56]> oxffff (02.03.2008 21:46:54) [54]
Если ты внимательно посмотришь, то увидишь, что я ничего не говорил про managed типы, а только про простые, к которым относится и интегер. А что сделает компилятор в этом случае его дело, хочет значение передает, хочет ссылку.
← →
{RASkov} © (2008-03-02 21:54) [57]> [54] oxffff © (02.03.08 21:46)
Эх... в такие моменты хочется как в былые времена... за кружечкой пива... обсудить вопросы.
Это я к тому что пить бросил, а [54] на "финском" все...
:о)
← →
oxffff © (2008-03-02 21:57) [58]
> Anatoly Podgoretsky © (02.03.08 21:52) [56]
Ваши слова
Anatoly Podgoretsky © (02.03.08 14:28) [7]
> {RASkov} (02.03.2008 14:20:06) [6]
>Ссылки для интегер работают медленнее значений.
Утверждая что
procedure abc(i:integer);
begin
end;
работает иначе от
procedure abcEx(const i:integer);
begin
end;
В данном случае идентично. Про var речи не было.
← →
oxffff © (2008-03-02 21:57) [59]
> {RASkov} © (02.03.08 21:54) [57]
> > [54] oxffff © (02.03.08 21:46)
>
> Эх... в такие моменты хочется как в былые времена... за
> кружечкой пива... обсудить вопросы.
> Это я к тому что пить бросил, а [54] на "финском" все...
>
> :о)
Там краце часть на русском.
← →
Loginov Dmitry © (2008-03-02 22:00) [60]> Без оптимизатора попробуй. Чтобы компилятор не пропускал
> код, если нет зависимости.
Ну причем тут оптимизатор? В курсе, что строки в процедуру всегда передаются по ссылке? А уже внутри процедуры, если идет обращение к элементам строки, компилятор может при отсутствии Const вставить вызов UniqueString(), и только после выполнения данной команды произойдет создание в памяти новой строки с необходимой коррекцией счетчика ссылок. Так что твои тесты, повторюсь еще раз - некорректные!
← →
{RASkov} © (2008-03-02 22:01) [61]Да.... много нового в ветке:
-Длинный параметр
-Короткий параметр
-managed типы
-простые наконец...) Ужас какой.... как я раньше жил....:)
И что значит:
> А что сделает компилятор в этом случае его дело, хочет значение
> передает, хочет ссылку.
Как это так?
> [59] oxffff © (02.03.08 21:57)
На русском-то я как раз прочитал без проблем :)
← →
Anatoly Podgoretsky © (2008-03-02 22:03) [62]> oxffff (02.03.2008 21:57:58) [58]
Мои и где ты тут противоречие видишь?
Компилятор решил передать значение, зачем передавать ссылку, если значение переменной все равно не удастся изменить. А вот если будет передача ссылки на интегер "Ссылки для интегер работают медленнее значений", то вот это и будет, поскольку обращение к A^ медленнее чем к А и тем более к регистру и особенно, когда в функции никак это не использует.
Похоже всех зачаровало слово const, почему то решили, что это имеет отношение к ссылка, ан нет, только к тому, что значение не будет изменено и ничего более. Я не помню кто этот гад, который поставил знак равенства.
← →
oxffff © (2008-03-02 22:04) [63]
> Loginov Dmitry © (02.03.08 22:00) [60]
Съезжаешь?
Здесь операция копирования
Причем здесь вообще UniqueString?
Loginov Dmitry © (02.03.08 19:05) [19]
1) это ничего не даст. Просто нельзя будет изменять значение переменной в процедуре, вот и все.
2) const и var при передаче глобальных переменных является потенциальной проблемой в многопоточном приложении.
А переменные String передавать с Const - это скорее правило хорошего тона. Именно в примере [2] оптимизации от этого никакой нет, т.к. нет обращения к отдельным символам строки
Прикинь разница есть между
procedure abc(s:string);
begin
......
end;
procedure abcEx(const s:string);
begin
......
end;
Даже если ...... одинаковые.
Или ты опять уже отказываешься от своих слов [19]
А переменные String передавать с Const - это скорее правило хорошего тона. Именно в примере [2] оптимизации от этого никакой нет, т.к. нет обращения к отдельным символам строки
← →
{RASkov} © (2008-03-02 22:11) [64]> [62] Anatoly Podgoretsky © (02.03.08 22:03)
Более-менее прояснилось... у меня. Спасибо.
> Я не помню кто этот гад, который поставил знак равенства.
Если нужно будет запинать - я помогу :)
← →
Anatoly Podgoretsky © (2008-03-02 22:11) [65]
> procedure abc(s:string);
> procedure abcEx(const s:string);
В обеих случай строку изменить не удастся.
← →
oxffff © (2008-03-02 22:11) [66]
> Anatoly Podgoretsky © (02.03.08 22:03) [62]
Разговор шел о процессе передачи.
А именно если идет передача по ссылке для value и const.
То для value в процедуре будет все равно создана копия в стеке + расходы на addref/Finalize. А для const нет.
И в данном конкретном случае передача по значению.
НО!!! Скорость работы с параметром (использование) здесь не велась. Только процесс передачи и возврата.
← →
Loginov Dmitry © (2008-03-02 22:13) [67]> Даже если ...... одинаковые.
Вот уже и "......" откуда-то взялось. А ведь процедуры сначалу пустыми были.
> Или ты опять уже отказываешься от своих слов [19]
Я ни в коем случае не отказываюсь ни от одного своего слова, сказанного в данной ветке. Если какое-либо мое утверждение в этой ветке на твой взгляд является ошибочным, то укажи его, скажи, что именно на твой взгляд в нем неправильно и как по-твоему оно есть на самом деле. А то, чувствую, идут прения "ни о чем".
← →
Anatoly Podgoretsky © (2008-03-02 22:13) [68]Я знаю как это работает для строк.
А вы решили видимо опять в который раз развить большую ветку.
← →
oxffff © (2008-03-02 22:14) [69]
> Anatoly Podgoretsky © (02.03.08 22:11) [65]
>
> > procedure abc(s:string);
>
> > procedure abcEx(const s:string);
>
> В обеих случай строку изменить не удастся.
Это только для string у нее такова семантика,
так как явные изменения "нормальные" (распознаваемые компилятором) добавляется вызов UniqueString. А для dyna array нет.
← →
oxffff © (2008-03-02 22:16) [70]
> Loginov Dmitry © (02.03.08 22:13) [67]
Согласно [19] ты утверждал, что разницы между
procedure abc(s:string);
begin
......
end;
procedure abcEx(const s:string);
begin
......
end;
Нет. Тебе показали, что это не так.
Пятый раз спросишь где показали?
← →
{RASkov} © (2008-03-02 22:20) [71]> [66] oxffff © (02.03.08 22:11)
Я так понял, что для параметров Integer легче(быстрее) копию передать, нежели работать с ихими ссылками....
Опять же.... для In64 уже через const передается:function StrToInt64Def(const S: string; const Default: Int64): Int64;
var
E: Integer;
begin
Val(S, Result, E);
if E <> 0 then Result := Default;
end;
Сумбурно..... но без пива здесь уже никак наверное.... :) ВоПщем нужно в ЦПУ_Виндоу смотреть..... жаль только я там не секу :(
← →
Loginov Dmitry © (2008-03-02 22:22) [72]> Согласно [19] ты утверждал, что разницы между .... Нет
Вот именно!
> Тебе показали, что это не так.
Да никто до сих пор не показал, что это не так! Один ты только пытаешься это доказать. Причем доказательств ты никаких не представляешь. Только какие-то надуманные тэсты с GetTickCount, которые не говорят ни о чем! Абсолютно ни о чем! Ты же что-то свое отстаиваешь, приводя ShowMessage, как "убедительный" довод.
← →
Anatoly Podgoretsky © (2008-03-02 22:25) [73]> oxffff (02.03.2008 22:11:06) [66]
Ну ты говоришь про строки, а претензии ко мне по Интегер :-)
Я разве спорю, я могу только повторить, я в курсе как на данный момент передаются строки, во всех трех вариантов и знаю как использовать все три.
← →
Anatoly Podgoretsky © (2008-03-02 22:26) [74]> oxffff (02.03.2008 22:14:09) [69]
И для динамических массивов я тоже знаю, там же копия не создается.
← →
oxffff © (2008-03-02 22:27) [75]
> {RASkov} © (02.03.08 22:20) [71]
Для value передачи всегда создается копия в стеке.
Если вызывающий передает ссылку (так выбрал компилятор), то в процедуре будет код, который создаст копию в стеке.
А для const нет (не будет копии в случае передачи ссылки).
Здесь только отладчик поможет. :)
← →
oxffff © (2008-03-02 22:34) [76]
> Loginov Dmitry © (02.03.08 22:22) [72]
> > Согласно [19] ты утверждал, что разницы между .... Нет
>
>
> Вот именно!
>
>
> > Тебе показали, что это не так.
>
>
> Да никто до сих пор не показал, что это не так! Один ты
> только пытаешься это доказать. Причем доказательств ты никаких
> не представляешь. Только какие-то надуманные тэсты с GetTickCount,
> которые не говорят ни о чем! Абсолютно ни о чем! Ты же
> что-то свое отстаиваешь, приводя ShowMessage, как "убедительный"
> довод.
Для особо непоняливых
procedure abc(s:string);
begin
......
end;
Код включает Addref + try finally finalize(LStrClr)
В
procedure abcEx(const s:string);
begin
......
end;
этого нет.
Для особо непоняливых
Если ты не понял, то тебе в клинику.
← →
oxffff © (2008-03-02 22:36) [77]
> Anatoly Podgoretsky © (02.03.08 22:25) [73]
> > oxffff (02.03.2008 22:11:06) [66]
>
> Ну ты говоришь про строки, а претензии ко мне по Интегер
> :-)
> Я разве спорю, я могу только повторить, я в курсе как на
> данный момент передаются строки, во всех трех вариантов
> и знаю как использовать все три.
См. [66]
И в данном конкретном случае передача по значению.
-> следовательно [7] неверно для [6].
← →
{RASkov} © (2008-03-02 22:40) [78]> [75] oxffff © (02.03.08 22:27)
> А для const нет (не будет копии в случае передачи ссылки).
Но если я верно понял [62], то при конст не ссылка передается, а как удумает компилятор... т.е. запросто может и скопироваться значение....
Странно все это :)
← →
oxffff © (2008-03-02 22:46) [79]
> {RASkov} © (02.03.08 22:40) [78]
Компилятор решает как передать ссылку или значение
как для value передачи, так и для const передачи.
Разница в том, что при передачи ссылки при value передачи, в процедуре будет создана копия все равно.
+К этим затратам можно отнести addref/finalize для managed типов.
А для const передачи этого не будет.
← →
Игорь Шевченко © (2008-03-02 23:11) [80]Вопрос был про Integer, а флейм развели на 4 страницы
← →
Loginov Dmitry © (2008-03-02 23:13) [81]> Код включает Addref + try finally finalize(LStrClr)
Это уже действительно убедительно, и мне к сожалению, нужно признать, что я не прав. Не думал, что компилятор будет вставлять try...finally, даже если процедура пустая. Я бряку ставил на END, и в ассемблерном коде просто не заметил ничего, кроме pop ebp и ret.
А твой тест с ShowMessage по преждему так и есть - некорректный. Он показывает, что быстрее (без оптимизации у меня - в 13 раз) выполняется второй цикл (не важно, какой именно). И это несмотря на наличие дополнительных 2х десятков машинных команд, связанных с реализацией try..finally.
Под фразой
> Именно в примере [2] оптимизации от этого никакой нет, т.к.
> нет обращения к отдельным символам строки. В других же случаях наличие
> Const может заметно улучшить производительность приложения по сравнению с его отсутствием.
я имею ввиду, что при отсутствии Const в процедуре будут присутствовать дополнительные машинные команды. Но без задержек на UniqueString их влияние на производительность программы настолько ничтожно, что на написание дополнительного слова Const в некоторых случаях можно смело забить. В таких случаях оптимизация, достигнутая с использованием Const, не ощущается.
← →
Anatoly Podgoretsky © (2008-03-03 02:02) [82]Const это не производительность, а защита
← →
Германн © (2008-03-03 02:30) [83]
> Anatoly Podgoretsky © (03.03.08 02:02) [82]
>
> Const это не производительность, а защита
>
Угу. Это защита от дурака. Или от умного в неадекватном состоянии.
Что увеличивает умному широту маневра, в т.ч. и с точки зрения повышения производительности. Но и ИШ в
> Игорь Шевченко © (02.03.08 23:11) [80]
полностью прав.
← →
Riply © (2008-03-03 03:03) [84]> [80] Игорь Шевченко © (02.03.08 23:11)
> Вопрос был про Integer, а флейм развели на 4 страницы
Не все всё знают.
Мне, например, было интересно (надеюсь и полезно) почитать эту ветку :)
← →
Германн © (2008-03-03 03:23) [85]
> Riply © (03.03.08 03:03) [84]
>
> > [80] Игорь Шевченко © (02.03.08 23:11)
> > Вопрос был про Integer, а флейм развели на 4 страницы
>
> Не все всё знают.
> Мне, например, было интересно (надеюсь и полезно) почитать
> эту ветку :)
>
Ну хоть тебе это пошло в плюс. Уже хорошо. Меньше будет попыток "ненаучного тыка" в очевидных случаях".
← →
oxffff © (2008-03-03 08:40) [86]
> Loginov Dmitry © (02.03.08 23:13) [81]
> > Код включает Addref + try finally finalize(LStrClr)
>
>
> Это уже действительно убедительно, и мне к сожалению, нужно
> признать, что я не прав. Не думал, что компилятор будет
> вставлять try...finally, даже если процедура пустая. Я бряку
> ставил на END, и в ассемблерном коде просто не заметил ничего,
> кроме pop ebp и ret.
> А твой тест с ShowMessage по преждему так и есть - некорректный.
> Он показывает, что быстрее (без оптимизации у меня - в
> 13 раз) выполняется второй цикл (не важно, какой именно).
> И это несмотря на наличие дополнительных 2х десятков машинных
> команд, связанных с реализацией try..finally.
отключи оптимизацию.
И делай rebuild.
И тест будет показывать разницу в виде задержек именно на Addref/finalize+try finally.
← →
oxffff © (2008-03-03 08:47) [87]
> Германн © (03.03.08 03:23) [85]
>
> > Riply © (03.03.08 03:03) [84]
> >
> > > [80] Игорь Шевченко © (02.03.08 23:11)
> > > Вопрос был про Integer, а флейм развели на 4 страницы
> >
> > Не все всё знают.
> > Мне, например, было интересно (надеюсь и полезно) почитать
>
> > эту ветку :)
> >
>
> Ну хоть тебе это пошло в плюс. Уже хорошо. Меньше будет
> попыток "ненаучного тыка" в очевидных случаях".
см. oxffff © (02.03.08 16:10) [15].
Очевидный случай?
Страницы: 1 2 3 вся ветка
Форум: "Начинающим";
Текущий архив: 2008.03.30;
Скачать: [xml.tar.bz2];
Память: 0.73 MB
Время: 0.044 c