В продолжение обсуждения передачи группы в C-функции как константы а не по ссылке. Как удалось выяснить, такие группы действительно копируются на стек по полям и делает это вызывающая программа. Так что, увы, нет нормального способа использовать такие функции из Клариона! Если нет возможности «развернуть» такие группы по полям, то единственный выход — использовать переходник.
Кстати! Оказывается есть возможность работы с C-функциями, которые возвращают в качестве результата структуру.
Типа:
my_struct MyFunc();
Данная функция возвращает структуру my_struct. На самом деле компилятор С генерит вызов такой функции как Clarion-аналог:
MyFunc(*MY_STRUCT _Struct),LONG,RAW,C,NAME('_MyFunc')
Т.е. в качестве первого (скрытого) параметра такая функция получает указатель на принимающую структуру и одновременно такая функция возвращает еще и указатель на эту структуру.
Вот такие дела.
Правда непонятно — все-ли C-компиляторы генерят подобный код?
Или это — типа «визитной карточки» отдельных компилятор?
NT>А если разворачивать, то в каком порядке должны идти поля и байты в строках?
NT>WBR, Nick Tsigouro Mailto:N.Tsigouro@mtu-net.ru
Структура «запихивается» на стек как байтовый массив. Но, так как стековые команды работают не с байтами а со словами, то и забрасывается группа по словам а не по полям. Если тип полей группы имеет одинаковый размер со словом в текущем режиме адресации (16/32 бита), то можно сказать, что на стек группа забрасывается по полям, начиная с последнего. Т.е. в результате на вершине стека окажеться первое поле группы.
Например:
typedef struct my_group { int field1,field2; } my_group; int my_func(my_group);
На Кларионе, интерфейс для вызова функции my_func будет выглядеть так:
MAP MODULE('C_LIB') my_func(LONG _Field1,LONG _Field2),LONG,C,NAME('_my_func') END END My_Group GROUP Field1 LONG Field2 LONG END ... Sum# = my_func(My_Group.Field1,My_Group.Field2) ...
Согласно декларации и аттрибуту «C», перед вызовом функции my_func, Кларион «забросит» на стек сначала Field2 а потом и Field1. В результате, на вершине стека будет Field1 а за ним Field2. Именно такую последовательность и ожидает получить на стеке функция my_func.
Проблемы начинаются, когда поля группы разного типа и/или размер этих типов не равен размеру слова. На стеке все эти данные выстраиваются так, как и стояли в группе. Но проблема в том, как все это выполнить на Кларионе.
Скажем, если предыдущая группа будет такой:
typedef struct my_group { short int field1,field2; } my_group;
При таком раскладе C-компилятор «загоняет» всю структуру на стек одной командой PUSH (для 32-битного режима). А функция уже «снимает» со стека по полям. На Кларионе не достаточно задекларировать эту функцию так:
MAP MODULE('C_LIB') my_func(SHORT _Field1,SHORT _Field2),LONG,C,NAME('_my_func') END END
В этом случае компилятор Клариона «забросит» на стек эти параметры как два слова. А функция ожидает эти параметры размещенными в одном слове. В данном случае можно решить эту проблему так:
MAP MODULE('C_LIB') my_func(LONG _Param),LONG,C,NAME('_my_func') END END LOC:Param LONG LOC:ParamGrp GROUP,OVER(LOC:Param) Field1 SHORT Field2 SHORT END ... LOC:ParamGrp.Field1 = 100 LOC:ParamGrp.Field1 = 200 A# = my_func(LOC:Param) ...
Ну а для более сложных структур, естественно, прийдется хорошенько «поламать» голову! Хотя, в общем виде, достаточно наложить на нужную стрктуру группу из LONG-полей (для 32-битного режима) такого размера, что-бы она перекрывала группу данных и использовать поля этой группы как параметры для вызова «сложной» C-функции. Честно говоря, я не знаю как C-компилятор поступает со структурами, содержащими байтовые поля и строки. Возможно, что так-же как и описано выше. Вообщем — пробовать надо.
Вообще-то, что-то мне не нравятся такие библиотеки, которые используют для вызовов PUBLIC-функций механизмы передачи параметров, не предназначенные для внешнего использования. Я что-то еще не встречал в библиотеках, предназначеных для внешнего использования, функции со структурами-параметрами, которые передавались-бы не по ссылке (адресу) а как константы. Хотя, возможно, я не прав.