Длина массива, различие в Delphi и FPC[Решено]

Форум для изучающих FPC и их учителей.

Модератор: Модераторы

Длина массива, различие в Delphi и FPC[Решено]

Сообщение Maxizar » 15.03.2011 15:11:26

Динамический массив, область памяти, на которую указывает переменная данного типа. Но это так же чуть больше чем просто массив, у динамического есть еще длина и счетчик ссылок.
Так вот скажем процедура Length возвращает длину массива и в Delphi и в FPC одну и туже Ура.
Когда же мы пытаемся узнать ее средствами ASM, тобишь копаясь в памяти, я получил такую не приятную вещь, FPC хранит в памяти где лежит Length, число которое меньше чем вернет процедура Length на 1.

Предположим имеем такой тип данных:
Код: Выделить всё
TIntArray2 = array  of integer;

Напишем процедуру тестирования:
Код: Выделить всё
procedure TForm1.Button1Click(Sender: TObject);
var D1:TIntArray2;
begin
    SetLength(D1,5);
   caption:=IntToStr(Len(D1))+' '+IntToStr(Length(D1));
end;

Где процедура Len написана нами на асме:
Для Delphi 2009:
Код: Выделить всё
function Len(var D:TIntArray2):Integer; register;assembler;
asm
  mov eax,[eax]
  mov eax,[eax-4]
end;


И для FPC:
Код: Выделить всё
function Len(var D:TIntArray2):Integer; register;assembler;
{$ASMMODE intel}
asm
  mov eax,[eax]
  mov eax,[eax-4]
end; 


Проводим тест, и получаем результат:
Delphi: Length(D1)=5, Len(D1)=5.
FPC: Length(D1)=5, Len(D1)=4.
Вопрос: Почему?

Lazarus 0.9.29 FPC 2.4.2.
Последний раз редактировалось Maxizar 16.03.2011 12:21:11, всего редактировалось 1 раз.
Maxizar
постоялец
 
Сообщения: 385
Зарегистрирован: 20.03.2010 19:48:14

Re: Длина массива через указатель, различие в Delphi и FPC

Сообщение Sergei I. Gorelkin » 15.03.2011 15:38:22

В FPC это то значение, которое возвращает ф-ция high() - на единицу меньше чем length.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1405
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Длина массива через указатель, различие в Delphi и FPC

Сообщение Maxizar » 15.03.2011 15:57:34

Да получается, что так, зачем они так сделали не понятно.. Теперь получается чтобы вернуть, указатель на динамический массив, который скажем сгенерировала функция из DLL написанная на Delphi, просто так не получится, нужно будет подправить, число которое записано по смещение -4 от-но указателя на массив...
Мда, зачем разработчики, делают отличия, в тех местах, где вроде бы нужно стремится сделать тютелька в тютельку...

А заметил то, чисто случайно. Переписываю процедуру для БПФ, на асм.. и тут бабах... фигня такая, прочитал книги, которые есть по сабжу, полез в гугл, везде длина массива.. а тут High получается... Обидно :( :evil:
Смысл теперь юзать Delphi mod.... Вот такими мелочами, меня растраивают разработчики FPC :( :? :(

Добавлено спустя 17 минут 11 секунд:
Но {$MODE DELPHI} не помогает... Мдя... либо последний не корректно работает в этом случае ((
Maxizar
постоялец
 
Сообщения: 385
Зарегистрирован: 20.03.2010 19:48:14

Re: Длина массива через указатель, различие в Delphi и FPC

Сообщение devels » 16.03.2011 00:11:23

Чем вас не устраивает обычный Length ? Или он медленнее?
devels
постоялец
 
Сообщения: 137
Зарегистрирован: 01.09.2010 12:14:38

Re: Длина массива через указатель, различие в Delphi и FPC

Сообщение Maxizar » 16.03.2011 01:01:00

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. :( Вот это меня и растраивает :cry:
Выход, либо внутри блока Asm вызывать процедуру Length, чего не хотелось... :(
А использование директивы Delphi mode, ничего не меняет, FPC все равно генерит для поля Length не длину массива, а максимальный элемент тобишь High.
Maxizar
постоялец
 
Сообщения: 385
Зарегистрирован: 20.03.2010 19:48:14

Re: Длина массива через указатель, различие в Delphi и FPC

Сообщение devels » 16.03.2011 08:18:38

Ну может для fpc прибавлять +1:


Код: Выделить всё
mov eax,[eax]
mov ecx,[eax-4]
{$ifdef FPC}
add eax, 1
{$endif}
devels
постоялец
 
Сообщения: 137
Зарегистрирован: 01.09.2010 12:14:38

Re: Длина массива через указатель, различие в Delphi и FPC

Сообщение Иван Шихалев » 16.03.2011 08:48:11

Maxizar писал(а):Но получается, что так нельзя делать, если данный код будет находится в ДЛЛ и работать с динамичискими массивами, которы будут создаваться в другом языке отличным от Free Pascal.


Именно нельзя. Другой язык вообще не обязан понимать, что такое динамический массив в object pascal-трактовке.
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Re: Длина массива через указатель, различие в Delphi и FPC

Сообщение Maxizar » 16.03.2011 12:20:22

devels писал(а):Ну может для fpc прибавлять +1:

Нет, просто получается, что нужно либо иметь две разных DLL или две разных функции, для FPC и Delphi..

Иван Шихалев писал(а):Именно нельзя. Другой язык вообще не обязан понимать, что такое динамический массив в object pascal-трактовке.

Да, тут так именно и происходит, что не обязан. Просто я думал что динамические массивы, который сделает и Delphi и FPC, должны быть одинаковыми, теперь знаю, что нет.

Просто я думал, что поле Length, будет одинаковым, и изночально подумал не баг ли... но оказывается, что нет...

И на будущее, вот где для Free Pascal, написаны такие тонкости... или чтобы это понять, нужно сидеть с дебаггером или читать исходный код FPC? Или я опять не там искал :(

PS. Спасибо, вопрос буду считать решенным.
Maxizar
постоялец
 
Сообщения: 385
Зарегистрирован: 20.03.2010 19:48:14


Вернуться в Обучение Free Pascal

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 26

Рейтинг@Mail.ru