devels писал(а):Чем вас не устраивает обычный Length ? Или он медленнее?
Тем, что я вообще не хотел вызывать процедуру Length в своем асм коде... она просто лишняя, и думал справится простым обращением через смещение -4. для динамического массива.
Но получается, что так нельзя делать, если данный код будет находится в ДЛЛ и работать с динамичискими массивами, которы будут создаваться в другом языке отличным от Free Pascal.
Пример:
DLL в которой одна функция суммирующая элементы массива:- Код: Выделить всё
library ASMDinArray;
{$mode objfpc}{$H+}
uses
Classes
{ you can add units after this };
type
TIntArray2 = array of integer;
{$R *.res}
function Sum1(var A:TIntArray2):Integer;Register;assembler;
{$ASMMODE intel}
asm
mov EAX,[EAX]
mov ECX,[EAX-4]
//dec ECX
mov EDX,[EAX]
@Summ:
add EAX,4
add EDX,[EAX]
loop @Summ
mov EAX,EDX
end;
Exports
Sum1 index 1;
begin
end.
Вызываем ее в программе написанной на Lazarus:- Код: Выделить всё
unit Unit1;
{$mode objfpc}
//{$MODE DELPHI}
{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Memo1: TMemo;
procedure Button2Click(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
TIntArray2 = array of integer;
var
Form1: TForm1;
implementation
function Sum1(var A:TIntArray2):Integer;Register; External 'project2.dll';
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button2Click(Sender: TObject);
var D1:TIntArray2;
begin
SetLength(D1,3);
D1[0]:=1;
D1[1]:=2;
D1[2]:=3;
caption:=IntToStr(Sum1(D1));
end;
end.
Тестируем, видим что отработали хорошо, в название формы вернули число 6;
Теперь хотим использовать данную Dll
в программе написанной на Delphi:- Код: Выделить всё
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TIntArray2 = array of integer;
var
Form1: TForm1;
implementation
{$R *.dfm}
function Sum1(var A:TIntArray2):Integer;Register; External 'project2.dll';
procedure TForm1.Button1Click(Sender: TObject);
var D1:TIntArray2;
begin
SetLength(D1,3);
D1[0]:=1;
D1[1]:=2;
D1[2]:=3;
caption:=IntToStr(Sum1(D1));
end;
end.
Видим вернули чушь. А все потому что FPC и Delphi генерируют в памяти динаммические массивы один в один,
кроме поля Length. по смещение -4 относительно указателя (переменной) массива.
Тобишь чтобы библиотека работала вместе с Делфи, нужно ее переписать вот так:
- Код: Выделить всё
function Sum1(var A:TIntArray2):Integer;Register;assembler;
{$ASMMODE intel}
asm
mov EAX,[EAX]
mov ECX,[EAX-4]
dec ECX
mov EDX,[EAX]
@Summ:
add EAX,4
add EDX,[EAX]
loop @Summ
mov EAX,EDX
end;
Добавили вот это:- Код: Выделить всё
dec ECX
Потому что эти поля отличаются на еденицу....
Вот это меня и возмутило, я думал что это Бага, но
Sergei I. Gorelkin, говорит, что это принципиально так сделано (я предпологаю, что из за того, что считается мол процедура High используется наиболее часто).
Поэтому я не могу так писать, используя поле Length, для использования библиотеки как в FPC так и в Delphi.
Вот это меня и растраивает
Выход, либо внутри блока Asm вызывать процедуру Length, чего не хотелось...
А использование директивы Delphi mode, ничего не меняет, FPC все равно генерит для поля Length не длину массива, а максимальный элемент тобишь High.