OberonCore https://forum.oberoncore.ru/ |
|
Проблемы с передачей массивов https://forum.oberoncore.ru/viewtopic.php?f=2&t=119 |
Страница 1 из 2 |
Автор: | Андрей [ Среда, 22 Февраль, 2006 11:27 ] |
Заголовок сообщения: | Проблемы с передачей массивов |
Здравствуйте! Подскажите, кто знает, как решить нижеописанную проблему. Итак... в BlackBox набран следующий модуль: Код: MODULE MyDll; (* sample module to be linked into a dll *) PROCEDURE ArrayIncrement*(VAR x: ARRAY OF INTEGER); VAR i: INTEGER; BEGIN FOR i := 0 TO LEN(x) - 1 DO INC(x[i]); END; END ArrayIncrement; END MyDll. Откомпилирован он в статическую dll командой Код: DevLinker.LinkDll MyDll.dll := MyDll# ~ В программе на Delphi 7 процедура ArrayIncrement объявлена как Код: PROCEDURE ArrayIncrement(VAR x: array of integer); stdcall; external 'MyDll.dll'; Использующая процедуру ArrayIncrement процедура: Код: procedure TForm1.Button2Click(Sender: TObject);
var i: integer; a: array [0..4] of integer; begin for i:= 0 to 4 do begin a[i] := 0; end; ArrayIncrement(a); end; При вызове ArrayIncrement(a); генерируется исключение "External exception C000001D". Как исправить эту ошибку? Как правильно передавать параметры в процедуры Компонентного Паскаля из процедур, написанных на других языках? Почему НИГДЕ не описан способ передачи параметров в Обероноподобных языках? |
Автор: | Сергей Губанов [ Среда, 22 Февраль, 2006 11:44 ] |
Заголовок сообщения: | Re: Проблемы с передачей массивов |
Ничего удивительного. Тип ARRAY OF INTEGER в Component Pascal - это одно (обобщенный value-тип всех целочисленных массивов располагаемых в любых типах памяти), а тип array of integer в Delphi - это совсем пересовсем абсолютно другое (reference-тип динамического целочисленного массива). Поскольку в Delphi нет аналога типа ARRAY OF INTEGER, то единственный способ "передать" массив из Delphi в Blackbox это передать адрес нулевого элемента. А в Blackbox-е "поколдовать" с ним посредством SYSTEM. Андрей писал(а): Почему НИГДЕ не описан способ передачи параметров в Обероноподобных языках?
Всё описано. В Blackbox-е смотрите раздел Platform-Specific Issues. |
Автор: | Trurl [ Среда, 22 Февраль, 2006 12:58 ] |
Заголовок сообщения: | |
Код: PROCEDURE ArrayIncrement*(VAR x: ARRAY [untagged] OF INTEGER);
Однако, теперь LEN для x будет недоступна. |
Автор: | Илья Ермаков [ Среда, 22 Февраль, 2006 13:21 ] |
Заголовок сообщения: | |
Ваша проблема, так сказать о двух концах: 1) В ББ ARRAY OF INTEGER - это ТЭГОВЫЙ массив, т.е. массив, перед которым идет тег его типа (статического или, если массив выделен динамически, временного описателя). Поэтому к нему, например, можно применять LEN(a) - возвращается размер этого массива. Такие массивы можно передавать только внутри одного ББ - даже между двумя DLL, написанными на ББ - уже нельзя, т.к. сборщики мусора-то у них разные. Ваш модуль должен выглядеть так: MODULE MyDll; (* sample module to be linked into a dll *) IMPORT SYSTEM; (* Читайте Особенности платформы (Platform-Specific-Issues *) (* Говорим, что массив безтеговый. Размер передаем явно, т.к. без тега определить размер открытого массива невозможно *) PROCEDURE ArrayIncrement*(VAR x: ARRAY [untagged] OF INTEGER; n: INTEGER); VAR i: INTEGER; BEGIN FOR i := 0 TO n DO INC(x[i]) END END ArrayIncrement; END MyDll. С INTEGER нет проблем с выравниванием. А если бы передавали ARRAY OF BYTE, то надо было бы явно указать [noalign] или другое выравнивание и то же самое в Дельфе. 2) В Дельфе опять же, свои заморочки. VAR array of - открытый массив. По-моему, размер открытых массивов в Дельфе передается скрытым параметром в стеке, т.е. получаем несовместимость по параметрам. Посему можно использовать один из следующих вариантов: PROCEDURE ArrayIncrement(x: array of integer; n: integer); stdcall; external 'MyDll.dll'; (array of integer в Дельфе - это динамический массив, "указатель на массив" - что нам и надо) или Type IntArray = array [0..High(Integer) div 4 -1] of Integer; pIntArray = ^IntArray; procedure ArrayIncrement (x: pIntArray; n: integer); stdcall; external 'MyDll.dll'; procedure Test; VAR x: array [0..256] of integer; begin ArrayIncrement(@x, Length(x)) - только @ не забывать ставить... end; Я не на 100% уверен, т.к. Дельфу подзабыл изрядно - но попробуйте оба варианта, хотя бы один должен сработать. |
Автор: | Андрей [ Среда, 22 Февраль, 2006 14:08 ] |
Заголовок сообщения: | |
Огромное спасибо за советы! ![]() Почему у меня возникли такие вопросы? Дело в том, что мне (для диплома) необходимо написать модуль для обработки сигналов, основанной на нечеткой логике. Модуль должен быть каким-то образом включен в уже существующую программу, довольно специфичную, которая является виртуальным "пультом оператора". Программа эта написана на Дельфи. Именно легкость написания визуальных интерфейсов в этой среде, а также большая распространенность ее и компонентов к ней побудили использовать именно ее для работы над проектом. Программа была написана не мной, но с моим участием. (Я писал на C алгоритмы для объекта управления) Однако, недавно я узнал о существовании Компонентного Паскаля, прочитал много хвалебной информации в адрес этого языка (кстати, действительно конструктивной критики не нашел) и решил писать программу именно на этом языке. Тут и возникли описанные выше проблемы ![]() ![]() Так вот, я прошу Вашего совета, что мне лучше делать в данной ситуации: продолжить изучение Дельфи или Компонентного Паскаля? В BlackBox или в Delphi быстрее я добьюсь результата - работающую программу? Кстати, алгоритмы работы нечеткой логики уже готовы, то есть на бумаге на псевдоязыке расписано как и что должно выполняться! Заранее благодарю! |
Автор: | Trurl [ Среда, 22 Февраль, 2006 14:48 ] |
Заголовок сообщения: | |
Исходный пример должен бы работать, если бы не одна "мелочь". При вызове ArrayIncrement Delphi передает максимальный индекс, а ББ ожидает длину массива. |
Автор: | Илья Ермаков [ Среда, 22 Февраль, 2006 14:52 ] |
Заголовок сообщения: | |
Ну, я, конечно, лицо заинтересованное, но все-таки постараюсь быть объективным ![]() Мой опыт работы на Дельфи - более 5 лет. Параллельно полтора года - С++. По поводу второго ничего говорить не буду, а то опять holly war начнется ![]() IF ... THEN ELSE END вместо if then begin end else begin end - насколько легче, а? Язык полностью совместим с Java. Существует несколько реализаций трансляторов с КП в Java-код. Сама Oberon Microsystems разработала на BlackBox'e операционку реального времени JBed - для встроенных систем, в частности. Так там вообще модули на КП и Яве работают вместе, разделяя общую память и сборщик мусора. Компилятор для Borland JBuilder также делала Oberon Microsystems по заказу Borland на Компонентном Паскале. Наконец, сам язык очень стройный и красивый, нет никаких излишеств, но есть все, что нужно. А если говорить о среде выполнения - то динамическая модульность и сборка мусора очень весомые аргументы в сравнении с Win32-Delphi. А Delphi .NET - это уже отдельная история... И, наконец, последнее: Borland продает все свои разработки IDE. Если раньше речь шла только о "кризисе Дельфи", то сейчас можно говорить о том, что на ней поставлен крест. BlackBox же продолжает развиваться самой компанией, и достпуен в исходных кодах, поэтому ближайшие годы за его судьбу можно не опасаться. Если же понадобиться работать под .NET или JVM - то есть пакет GPCP. Так что, размышляйте, сравнивайте, решайте. Цитата: В BlackBox или в Delphi быстрее я добьюсь результата - работающую программу?
На моей практике программы в ББ получаются значительно более надежными, а ошибки обнаруживаются гораздо быстрее (не смотря на отсутсвие привычного многим пошагового отладчика). Кстати, встроенный профилировщик в ББ есть, поэтому оптимизировать также легче. |
Автор: | Илья Ермаков [ Среда, 22 Февраль, 2006 15:00 ] |
Заголовок сообщения: | |
Цитата: Исходный пример должен бы работать, если бы не одна "мелочь".
При вызове ArrayIncrement Delphi передает максимальный индекс, а ББ ожидает длину массива. Игорь, тогда я чего-то не догоняю: передавать-то передает, но в BB размер массива определяется по его тегу типа, и этот тег типа лежит в области памяти массива. А в Дельфе, кажется, информация об индексации открытого массива VAR array of... идет дополнительными параметрами в стеке. А у динамических массивов (без VAR) array of... размер лежит по смещению -4 от базового адреса, т.е. также совместимости с TAGGED ARRAY никакой нет... Али я не прав? |
Автор: | Trurl [ Среда, 22 Февраль, 2006 15:15 ] |
Заголовок сообщения: | |
Нет. Размер массива передается как еще один параметр. А без VAR это не динамический массив, это массив, для которого создается локальная копия в стеке. |
Автор: | Илья Ермаков [ Среда, 22 Февраль, 2006 15:20 ] |
Заголовок сообщения: | |
Стоп, стоп... PROCEDURE (a: array of integer) - это не статический открытый массив, таких в Дельфе просто нет. array of... - это как раз динамический массив, память под который выделяется SetLength. Фактически, указатель на массив. Я могу написать: VAR a, b: array of integer SetLength(a, 256); SetLength(b, 512); a := b - тут я присвою указатели, и a и b станут указывать на один массив. Посему PROCEDURE (a: array of integer) PROCEDURE (a: pIntArray) и PROCEDURE (VAR a: array [0..n] of char) на низком уровне абсолютно идентичны, в заголовках к внешним DLL в Дельфе с одинаковым успехом используют все три формы. |
Автор: | Trurl [ Среда, 22 Февраль, 2006 15:52 ] |
Заголовок сообщения: | |
Илья Ермаков писал(а): Стоп, стоп...
PROCEDURE (a: array of integer) - это не статический открытый массив, таких в Дельфе просто нет. Ну, я не о Дельфе. ![]() Впрочем, почему нет? Код: PROCEDURE p1(a: array of integer);
и PROCEDURE p2(VAR a: array of integer); отличаются только тем, что в p1 значение a ьбудет скопировано а стек. |
Автор: | Trurl [ Среда, 22 Февраль, 2006 16:08 ] |
Заголовок сообщения: | |
Trurl писал(а): Исходный пример должен бы работать, если бы не одна "мелочь".
Вот, попробовал. Код: procedure ArrayIncrement(VAR x: array of integer); stdcall; external 'MyDll.dll';
var i: integer; a: array [0..4] of integer; begin for i:= 0 to 4 do begin a[i] := 0; end; ArrayIncrement(a); for i:= 0 to 4 do begin writeln(a[i]); end; end. выводит 1 1 1 1 0 |
Автор: | Илья Ермаков [ Среда, 22 Февраль, 2006 17:03 ] |
Заголовок сообщения: | |
Да, Вы правы, в Дельфе это открытый массив, передаваемый по значению. Вот строчка из документации: The syntax of open array parameters resembles that of dynamic array types, but they do not mean the same thing. Вот он, еще один пример путаницы в Object Pascal, когда разные вещи называются абсолютно одинаково. Объявления TYPE A: array of integer; PROCEDURE P(a: A) и PROCEDURE p(a: array of integer) должны быть абсолютно идентичны, просто в одном случае тип объявлен явно, а в другом - по месту... На самом деле "две большие разницы" ![]() |
Автор: | Илья Ермаков [ Среда, 22 Февраль, 2006 17:07 ] |
Заголовок сообщения: | |
Цитата: Вот, попробовал.
Так что, форматы открытых массивов у Дельфи и ББ совпадают? И все равно, мне кажется, для любых данных, приходящих извне, надо использовать [untagged], мало ли какие побочные эффекты могут быть... |
Автор: | Сергей Губанов [ Среда, 22 Февраль, 2006 17:27 ] |
Заголовок сообщения: | |
Илья Ермаков писал(а): Так что, форматы открытых массивов у Дельфи и ББ совпадают? ...с точностью до разницы между High(a) и Length(a) ![]() Trurl писал(а): При вызове ArrayIncrement Delphi передает максимальный индекс, а ББ ожидает длину массива.
|
Автор: | Сергей Оборотов [ Среда, 22 Февраль, 2006 22:33 ] |
Заголовок сообщения: | |
Сергей Губанов писал(а): Илья Ермаков писал(а): Так что, форматы открытых массивов у Дельфи и ББ совпадают? ... до разницы между High(a) и Length(a) ![]() Было бы интересно поглядеть где именно это описано. Если бы вопрос сводился к количеству обрабатываемых элементов то была бы непонятна причина возниковения ошибки в вышеуказанном примере. Кстати откуда известно, что она возникла в результате вызова ArrayIncrement(a)? |
Автор: | Андрей [ Четверг, 23 Февраль, 2006 20:21 ] |
Заголовок сообщения: | |
Цитата: Кстати откуда известно, что она возникла в результате вызова ArrayIncrement(a)?
В Дельфе есть пошаговый отладчик... |
Автор: | Андрей [ Четверг, 23 Февраль, 2006 21:52 ] |
Заголовок сообщения: | |
Работает такой вариант: Код: MODULE MyDll; (* sample module to be linked into a dll *) IMPORT SYSTEM; PROCEDURE ArrayIncrement*(VAR x: ARRAY [untagged] OF INTEGER; num: INTEGER); VAR i: INTEGER; BEGIN FOR i := 0 TO num - 1 DO INC(x[i]); END; END ArrayIncrement; END MyDll. Delphi: Код: PROCEDURE ArrayIncrement(x: pointer; num: integer); stdcall; external 'MyDll.dll'; procedure TForm1.Button2Click(Sender: TObject); var i: integer; a: array [0..4] of integer; begin for i:= 0 to 4 do begin a[i] := 0; end; ArrayIncrement(@a[0], 5); end; После ArrayIncrement(@a[0], 5) все 5 элементов массива a равны 1. Информация к размышлению: 1) Любой из вариантов описания процедуры ArrayIncrement: Код: PROCEDURE ArrayIncrement(var x: array of integer; num: integer); stdcall; external 'MyDll.dll'; Код: PROCEDURE ArrayIncrement(x: array of integer; num: integer); stdcall; external 'MyDll.dll'; не проходит. После вызова процедуры с любым num, последний элемент массива a всегда равен 0(?!).
2) Вызов ArrayIncrement(@a[0], 500) не производит никакой исключительной ситуации(!); Цитата: И все равно, мне кажется, для любых данных, приходящих извне, надо использовать [untagged], мало ли какие побочные эффекты могут быть... Действительно, вчера исходный пример вызывал исключение, а сегодня, после перекомпиляции, выдавал то же самое, что и у Trurl: Цитата: выводит
1 1 1 1 0 |
Автор: | Илья Ермаков [ Четверг, 23 Февраль, 2006 23:50 ] |
Заголовок сообщения: | |
Цитата: После вызова процедуры с любым num, последний элемент массива a всегда равен 0(?!).
Видимо, как раз из-за дополнительного параметра-предела индексов, который Дельфа передает перед каждым открытым массивом. А [untagged]-открытый массив в ББ - это по сути просто указатель, без всякой скрытой информации. Я Вас тоже подзапутал с этими открытыми массивами, выше я уже написал про свою ошибку с array of... Самый нормальный вариант, как Вы и сделали - в ББ - untagged-массив, а в Дельфе - указатель. Можно указатель на массив, не обязательно именно pointer. |
Автор: | Сергей Оборотов [ Пятница, 24 Февраль, 2006 07:15 ] |
Заголовок сообщения: | |
Я конечно могу и ошибаться. По идее вариант Код: BlackBox:
PROCEDURE ArrayIncrement*(VAR x: ARRAY [untagged] OF INTEGER, index: INTEGER); Delphi: PROCEDURE ArrayIncrement(var x: array of integer); stdcall; external 'MyDll.dll'; должен работать. А если не работает надо узнать почему. Что нам по этому поводу говорит пошаговый отладчик? |
Страница 1 из 2 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |