Ошибка при изменении длины динамического массива

Вопросы программирования и использования среды Lazarus.

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

Ошибка при изменении длины динамического массива

Сообщение Alex. S » 21.02.2016 20:11:54

Отлаживаю dll, в которой есть процедуру, в которую я в качестве переменной передаю массив из программы. Проблема в том, что когда длина массива устанавливается в функции dll, программа завершается с ошибкой External "SIGSEGV". Если установить длину массива до вызова функции, в самой программе, всё нормально...

Использую такую структуру:
Часть кода из DLL:
Код: Выделить всё
...
TDWordArray = array of Cardinal;
...
procedure GetData(var Data: TDWordArray);
begin
//
SetLength(Data, 1);
//
Data[0]:=5;
end;


Частичный код программы:
Код: Выделить всё
...
type
//
  TDWordArray = array of Cardinal;

...
procedure GetData(Data: TDWordArray); external 'MyDLL.dll';

procedure TForm1.Button1Click(Sender: TObject);
var
//
i, k: Cardinal;
//
SomeData: TDWordArray;
begin
//
GetData(SomeData);

//
k:=Length(SomeData);
//
if k > 0 then
  begin
  //
  Dec(k);

  //
  for i:=0 to k do
  //
  ShowMessage(IntToStr(SomeData[i]));
  end;
end;
Alex. S
новенький
 
Сообщения: 39
Зарегистрирован: 22.08.2015 11:37:00

Re: Ошибка при изменении длины динамического массива

Сообщение Sharfik » 21.02.2016 20:34:27

Не уверен, но может сработает так
Код: Выделить всё
procedure TForm1.Button1Click(Sender: TObject);
var
//
i, k: Cardinal;
//
SomeData: TDWordArray;
begin
//
SetLength(SomeData,0);// Добавить эту строку

GetData(SomeData);

//
k:=Length(SomeData);
//
if k > 0 then
  begin
  //
  Dec(k);
  //
  for i:=0 to k do
  //
  ShowMessage(IntToStr(SomeData[i]));
  end;
end;
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 809
Зарегистрирован: 20.07.2013 01:04:30

Re: Ошибка при изменении длины динамического массива

Сообщение Alex. S » 21.02.2016 20:38:42

Sharfik, увы, всё равно ошибка :(
Alex. S
новенький
 
Сообщения: 39
Зарегистрирован: 22.08.2015 11:37:00

Re: Ошибка при изменении длины динамического массива

Сообщение Sharfik » 21.02.2016 21:01:14

1) Передавать SomeData безтолку, если он не инициализирован ранее.
2) DLL это новый поток/класс/область Application. Данные созданные Application относящемуся к DLL, не видны в основном Application. Но из основного видны в DLL.
Я не делал интерфейсы, поленился. Я создал абстрактные классы, и ими подгружая их в библиотеки манипулирую как куклой само приложение.
Можно создать класс TCustomArrayController и от него TArrayController. исходники первого прицепить в библиотеку.

Добавлено спустя 13 минут 21 секунду:
туплю...
Data: TDWordArray это переменная хранящая данные типа TDWordArray, и делая
procedure GetData(Data: TDWordArray); external 'MyDLL.dll';
передается копия данных, а не указатель на область памяти. Даже если она была инициализирована. И то кажется массивы передавать нельзя так, только через Record(где то встречал).
Когда передаются классы, то переменная передаваемая хранит адрес памяти объекта, а не все данные класса.
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 809
Зарегистрирован: 20.07.2013 01:04:30

Re: Ошибка при изменении длины динамического массива

Сообщение Alex. S » 21.02.2016 21:19:09

Sharfik, мысль про передачу SomeData вроде понял, а вот про TCustomArrayController не очень. Попробую завтра реализовать через классы, посмотрю, что получится :)
Alex. S
новенький
 
Сообщения: 39
Зарегистрирован: 22.08.2015 11:37:00

Re: Ошибка при изменении длины динамического массива

Сообщение Sharfik » 21.02.2016 21:26:23

TCustomArrayController другие меня помидорами закидают, но если нужен именно массив, то можно сделать класс который будет создаваться в нужный момент и управлять данными в массиве. Правильнее вроде с интерфейсами, но я в них не понимаю ничего.
Вот этот класс надо как модуль загрузить в проект и программы и библиотеки. Они должны быть идентичными. Класс описывается абстрактно в одном модуле, а сами процедуры реализуются во втором модуле, который не обязательно передавать в библиотеку.
Интерфейсы по сути делают тоже самое, что то типа абстрактного описания классов программы.
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 809
Зарегистрирован: 20.07.2013 01:04:30

Re: Ошибка при изменении длины динамического массива

Сообщение resident » 21.02.2016 22:33:42

А если в программу возвращать длину?
Код: Выделить всё
procedure GetData(var Data: TDWordArray; var DataLength: integer);
resident
энтузиаст
 
Сообщения: 605
Зарегистрирован: 13.03.2013 16:58:51

Re: Ошибка при изменении длины динамического массива

Сообщение Alex. S » 21.02.2016 23:11:19

Sharfik, это не Вы тупите, а я. Упустил слово var перед параметром процедуры.

Про вариант, который Вы предложили, я такого ещё не встречал. Мне уже действительно легче как resident предложил, вначале получать длину массива, устанавливать её, и потом заполнять его данными :lol: Обидно, что придётся тогда две процедуры прогонять, вместо одной. Снижается удобность :P

Ещё вопрос, пусть даже сделаю на интерфейсах, как потом со совместимостью с другими языками? Или получится, Object Pascal only? ;) Я и так думаю, сейчас уже думаю, получится ли использовать dll библиотеку, при разработке на Си и других языках...

P.S. Хотя я ж мучился, когда подключал чужие библиотеки, которые на Си писали, или ещё на чём-то, пусть теперь они мучаются, пытаясь мою подключить :mrgreen: В знак солидарности им...

P.S.S. Вообще, пришёл к выводу, что чем дольше я программирую, тем большее понимаю, что ничего не знаю толком ещё :)
Alex. S
новенький
 
Сообщения: 39
Зарегистрирован: 22.08.2015 11:37:00

Re: Ошибка при изменении длины динамического массива

Сообщение Sharfik » 22.02.2016 00:21:21

Классы или массивы - Object Pascal only
Если интерфейсы - тогда есть шанс, но надо использовать типы данных которые существуют в других языках.

Тебе стоит день потратить на блог GunSmoker-а, он много про плагины на Delphi писал.
http://www.gunsmoker.ru/2011/12/delphi.html
Правило номер шесть - вы не должны использовать типы данных Delphi, потому что они не имеют аналога в других языках. Например, string, array of, TObject, TForm (и вообще любые объекты и уж тем более компоненты) и т.п. Что можно использовать - целочисленные типы (Integer, Cardinal, Int64, UInt64, NativeInt, NativeUInt, Byte, Word и т.п.; я бы не рекомендовал использовать Currency, если только он вам действительно нужен), вещественные (Single и Double; я бы рекомендовал избегать типов Extended и Comp, если только они действительно вам нужны и иначе никак), перечислимые и subrange-типы (с некоторыми оговорками), символьные типы (AnsiChar и WideChar, но не Char), строки (только в виде WideString), логический тип (BOOL, но не Boolean), интерфейсы (interface), в методах которых используются допустимые типы, записи (record) из вышеуказанных типов, а также указатели на них (в том числе указатели на массивы из вышеуказанных типов, но не динамические массивы).
Аватара пользователя
Sharfik
энтузиаст
 
Сообщения: 809
Зарегистрирован: 20.07.2013 01:04:30

Re: Ошибка при изменении длины динамического массива

Сообщение Mirage » 22.02.2016 00:31:07

Alex. S: Как работают дин. массивы знаете? Про подсчет ссылок и т.п.
Надо, чтобы память, выделяемая в dll там же и освобождалась. А память, выделяемая в основном приложении освобождалась в нем же, т.к. менеджеры памяти по умолчанию разные. Если передавать дин. массив как var параметр вообще непонятно что получится. Основное приложение рано или поздно попытается освободить память в таком массиве и скорее всего упадет, если эту память не оно же выделяло.
Решение - хорошо подумать, нужна ли тут dll. Скорее всего нет.
Если таки нужна, то не передавать между приложением и .dll сущности с автоматически управляемым временем жизни. Т.е. строки, дин. массивы, интерфейсы (впрочем, они все равно специфичны для Паскаля). А передавать буферы, выделенные в куче и зорко следить за их правильным освобождением.
Насколько проблему решает общий менеджер памяти не проверял. И как он сказывается на возможности использовать эту dll из других языков тоже надо бы проверить.
Mirage
энтузиаст
 
Сообщения: 881
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Ошибка при изменении длины динамического массива

Сообщение Alex. S » 22.02.2016 11:47:57

Sharfik, Mirage, спасибо Вам за разъяснения...

В таком случае, буду делать процедуру получения количества элементов, далее, выделять память для указателя на массив, и передавать этот указатель, а не изменять длину массива, и передавать его. Если я равильно понял, так гораздо лучше...

Ещё пара вопросов:
1) В описании параметров нескольких процедур, я использую const, я так понимаю, его тоже лучше убрать... То есть, оставить передачу либо с var, либо без ничего...

2) Как правильно передать имя файла в функцию dll? Раньше использовал String, а как сейчас, даже не знаю.

P.S. Если просто поменять тип переменной результата с Boolean на Bool, но в программе присваивать этот результат переменной типа Boolean, это же нормально? Я знаю, что у этих типов различается значение для true, но, насколько понимаю, это не будет влиять на возможность получения ошибки...
Alex. S
новенький
 
Сообщения: 39
Зарегистрирован: 22.08.2015 11:37:00

Re: Ошибка при изменении длины динамического массива

Сообщение Лекс Айрин » 22.02.2016 11:55:10

Alex. S писал(а):В описании параметров нескольких процедур, я использую const, я так понимаю, его тоже лучше убрать...


А это зависит от ситуации. Иногда лучше оставить.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Ошибка при изменении длины динамического массива

Сообщение Alex. S » 22.02.2016 12:00:07

Лекс Айрин, а на других языках программирования потом проблемы не будет, из-за этого?

Прочитал, статью GunSmoker'а. Нашёл, что вместо String нужно использовать WideString, хотя ниже, в его коде используется String, а про WideString и упоминания нет :( Так как же правильно?
Alex. S
новенький
 
Сообщения: 39
Зарегистрирован: 22.08.2015 11:37:00

Re: Ошибка при изменении длины динамического массива

Сообщение Лекс Айрин » 22.02.2016 12:09:42

Alex. S, не должна бы быть. Var и Const в описании функций/процедур это скорее напоминание изменяется параметр или нет внутри подпрограммы. Для функций, кстати, хорошим тоном считается отсутствие побочных эффектов... т.е. параметры не должны изменяться, только результат. Для процедур, это не так, но все же желательно уменьшить побочные эффекты.
Последний раз редактировалось Лекс Айрин 22.02.2016 12:17:46, всего редактировалось 1 раз.
Аватара пользователя
Лекс Айрин
долгожитель
 
Сообщения: 5723
Зарегистрирован: 19.02.2013 16:54:51
Откуда: Волгоград

Re: Ошибка при изменении длины динамического массива

Сообщение Alex. S » 22.02.2016 12:16:00

Лекс Айрин, ясно, спасибо :)

Кстати, как правильно определить Bool, а не Boolean переменную? Это будет WordBool или LongBool?
Alex. S
новенький
 
Сообщения: 39
Зарегистрирован: 22.08.2015 11:37:00

След.

Вернуться в Lazarus

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

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

Рейтинг@Mail.ru