Как объявить процедурный тип для class ... static?

Общие вопросы программирования, алгоритмы и т.п.

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

Как объявить процедурный тип для class ... static?

Сообщение mgear » 01.02.2015 04:08:21

Нигде в интернетах ответа не смог найти. Или меня одного это интересует, или задачка не решается в рамках FPC. При этом в дельфи пашет как от нефиг делать.

Есть callback функции, объявленные через процедурный тип, чтобы использоваться во внешней библиотеке. Их там две штуки, но для простоты приведу одну:

Код: Выделить всё
type
  pcre2_malloc_func = function(size:PCRE2_SIZE; p:pointer):pointer; cdecl;
  function pcre2_general_context_create_16(malloc_f: pcre2_malloc_func; free_f: pcre2_free_proc; memory_data:pointer): p_pcre2_general_context; cdecl; external;

function pcre2_malloc_def(size:PCRE2_SIZE; p:pointer):pointer; cdecl;
begin
  Result := getmem(size);
end;

...
fgeneral_context := pcre2_general_context_create_16(@pcre2_malloc_def, @pcre2_free_def, nil);


Ну и как бы зашибись всё работает. Но это неаккуратненько, доктор. Потому что вспомогательная функция класса объявлена вне класса.

Мы-то на объектном языке пишем, и вызов используется в классе, так что идеологически верно было бы оформить в качестве метода и описать, естественно, как class static, чтоб вызывалась без селфов разных там.

Код: Выделить всё
    class function malloc_def(size:PCRE2_SIZE; p:pointer):pointer; cdecl; static;


Но в этом случае компилятор ругается:
Error: Incompatible type for arg no. 1: Got "<class method type of function(LongWord;Pointer):^untyped of object;CDecl>", expected "<procedure variable type of function(LongWord;Pointer):^untyped;CDecl>"


Причём в хелпе русским английским языком сказано следующее:
FPC knows static class methods in classes: these are class methods that have the Static keyword at the end. These methods behave completely like regular procedures or functions. This means that:

They do not have a Self parameter. As a result, they cannot access properties or fields or regular methods.
They cannot be virtual.
They can be assigned to regular procedural variables.


Выделено мною. Тем не менее, assign to regular procedural variable не фурычит.
mgear
новенький
 
Сообщения: 19
Зарегистрирован: 25.01.2015 19:29:56

Re: Как объявить процедурный тип для class ... static?

Сообщение Дож » 01.02.2015 15:00:15

Мне не удалось воспроизвести ошибку.
Код: Выделить всё
[doj@larion ~/temp]$ cat staticproc.pas
{$MODE DELPHI}
type
TFunc = function(Size: Integer; P: Pointer): Pointer; cdecl;
TMyObject = class
  class function malloc_def(Size: Integer; P: Pointer): Pointer; cdecl; static;
end;

class function TMyObject.malloc_def(Size: Integer; P: Pointer): Pointer;
begin
  Result := P;
end;

var
  F: TFunc;

begin
  F := TMyObject.malloc_def;
end.
[doj@larion ~/temp]$ fpc staticproc.pas
/usr/bin/ld: warning: link.res contains output sections; did you forget -T?
[doj@larion ~/temp]$
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: Как объявить процедурный тип для class ... static?

Сообщение kazalex » 01.02.2015 20:01:14

Дож писал(а):Мне не удалось воспроизвести ошибку.

{$MODE DELPHI} убери :)
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Re: Как объявить процедурный тип для class ... static?

Сообщение mgear » 02.02.2015 01:10:47

Я уж по-всякому корячился, но фантазия иссякла, а воз и ныне там. Даже принудительно тип указателя присвоить не получилось. Компилятор упирается. Не буду, - говорит, - компилировать и всё тут. Несоответствие, - говорит, - типов.

Моде дельфи не хочу. Не по-пацански это. Хочу уметь объявлять тип метода. А то прям как в той песенке получается: жопа есть, а слова нет.
mgear
новенький
 
Сообщения: 19
Зарегистрирован: 25.01.2015 19:29:56

Re: Как объявить процедурный тип для class ... static?

Сообщение kazalex » 02.02.2015 01:24:23

mgear писал(а):Даже принудительно тип указателя присвоить не получилось.

Хм, странно. У меня с приведением сработало.
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Re: Как объявить процедурный тип для class ... static?

Сообщение mgear » 02.02.2015 03:43:04

Ну ок, вот тестовый юнит. Он компилируется. Задача - раскомментировать строчку и скомпилять в режиме objfpc хоть через какое угодно переписывание методов и приведение типов.

Код: Выделить всё
unit Unit1;

{$mode objfpc}{$H+}

interface

type
  pcre2_malloc_func = function(size:longint; p:pointer):pointer; cdecl;
  pcre2_free_proc = procedure(p1:pointer; p2:pointer); cdecl;

  pcre2_general_context = record end;
  p_pcre2_general_context = ^pcre2_general_context;

  myclass = class
  private
     fgeneral_context: p_pcre2_general_context;
     class function malloc(size:longint; p:pointer):pointer; cdecl; static;
     class procedure free(p1:pointer; p2:pointer); cdecl; static;
  public
     procedure aaa;
  end;

function pcre2_general_context_create_16(malloc_f: pcre2_malloc_func; free_f: pcre2_free_proc; memory_data:pointer): p_pcre2_general_context; cdecl;

implementation

function _malloc(size:longint; p:pointer):pointer; cdecl;
begin
  Result := nil;
end;

procedure _free(p1:pointer; p2:pointer); cdecl;
begin
end;

function pcre2_general_context_create_16(malloc_f: pcre2_malloc_func;
  free_f: pcre2_free_proc; memory_data: pointer): p_pcre2_general_context;
  cdecl;
begin
  Result := nil;
end;

class function myclass.malloc(size: longint; p: pointer): pointer; cdecl;
begin
  Result := nil;
end;

class procedure myclass.free(p1: pointer; p2: pointer); cdecl;
begin

end;

procedure myclass.aaa;
begin
  fgeneral_context := pcre2_general_context_create_16(@_malloc, @_free, nil);
//  fgeneral_context := pcre2_general_context_create_16(@malloc, @free, nil);
end;

end.
mgear
новенький
 
Сообщения: 19
Зарегистрирован: 25.01.2015 19:29:56

Re: Как объявить процедурный тип для class ... static?

Сообщение kazalex » 02.02.2015 10:24:11

mgear писал(а):Задача - раскомментировать строчку и скомпилять в режиме objfpc хоть через какое угодно переписывание методов и приведение типов.

Код: Выделить всё
  fgeneral_context := pcre2_general_context_create_16(pcre2_malloc_func(@myclass.malloc), pcre2_free_proc(@myclass.free), nil);
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Re: Как объявить процедурный тип для class ... static?

Сообщение mgear » 02.02.2015 18:18:35

kazalex, спасибо!!!

Почему-то паскаль ругается "Error: Illegal type conversion" на pcre2_malloc_func(@malloc), при этом спокойно кушает pcre2_malloc_func(@myclass.malloc). Хотя вызов осуществляется из метода класса, так что уточнение "myclass.", вроде как, избыточное. Вот и поди догадайся. Хорошо хотя бы он не просит "unit1.myclass." :lol: :lol: :lol:
mgear
новенький
 
Сообщения: 19
Зарегистрирован: 25.01.2015 19:29:56

Re: Как объявить процедурный тип для class ... static?

Сообщение wavebvg » 04.02.2015 16:18:49

mgear писал(а):Почему-то паскаль ругается "Error: Illegal type conversion" на pcre2_malloc_func(@malloc), при этом спокойно кушает pcre2_malloc_func(@myclass.malloc). Хотя вызов осуществляется из метода класса, так что уточнение "myclass.", вроде как, избыточное. Вот и поди догадайся. Хорошо хотя бы он не просит "unit1.myclass." :lol: :lol: :lol:

Потому что Вы через ссылку на таблицу в Self пытается вызвать, что недопустимо для компилятора.
Просто это не предусмотрено в самом компиляторе, потому что class метод может быть виртуальным и тогда... Ну в общем тогда нужно все предусмотреть, так что проще запретить стрелять себе в голову, предварительно запретив стрелять в себя с открытыми глазами. Разименовав указатель и правильно пересчитав смещение вы можете вызвать всё, что угодно. Только оно Вам надо?
wavebvg
постоялец
 
Сообщения: 354
Зарегистрирован: 28.02.2008 04:57:35

Re: Как объявить процедурный тип для class ... static?

Сообщение mgear » 04.02.2015 18:33:34

wavebvg писал(а):Только оно Вам надо?

Мне (и, надеюсь, всем прочим юзверятам) надо, чтоб были методы статические без указателей, совместимые по типу с бесклассовыми процедурами. В дельфи они есть. В плюсах есть. В джаве есть. Во фри паскале их нет почему-то. По сути, это является диверсией и надругательством над психикой. Тем этом в официальном хелпе написано, что они есть. Как так?

То есть, если сравнивать с оружием, они мне продают ружжо без бойка с пропиленным стволом. Понятно, что в голову себе не стрельнёшь, но ведь и на зайцев-уток не поохотишься.
mgear
новенький
 
Сообщения: 19
Зарегистрирован: 25.01.2015 19:29:56

Re: Как объявить процедурный тип для class ... static?

Сообщение kazalex » 04.02.2015 18:59:22

mgear писал(а): По сути, это является диверсией и надругательством над психикой. Тем этом в официальном хелпе написано, что они есть. Как так?

Обычный баг, коих появляется вагон, как только начинаешь писать более-менее сложный код.
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Re: Как объявить процедурный тип для class ... static?

Сообщение mgear » 05.02.2015 00:10:44

kazalex, больше похоже на то, что сделано специально.
mgear
новенький
 
Сообщения: 19
Зарегистрирован: 25.01.2015 19:29:56

Re: Как объявить процедурный тип для class ... static?

Сообщение kazalex » 05.02.2015 00:29:46

mgear, по сообщению об ошибке видно же, что баг:
project1.lpr(53,85) Error: Incompatible type for arg no. 2: Got "<class method type of procedure(Pointer;Pointer) of object;CDecl>", expected "<procedure variable type of procedure(Pointer;Pointer);CDecl>"

Добавлено спустя 37 минут 21 секунду:
Вот еще прикол. В режиме {$mode delphi} прокатывает даже если у методов класса (malloc и free) полностью изменить сигнатуры :mrgreen:

Код: Выделить всё
class procedure myclass.free();
begin
end;

procedure myclass.aaa;
begin
  fgeneral_context := pcre2_general_context_create_16(@myclass.malloc, @myclass.free, nil);
end;

Проверено на транковом компиляторе.

Добавлено спустя 14 минут 51 секунду:
Но если убрать оператор взятия адреса, то прокатывать перестает :)
kazalex
постоялец
 
Сообщения: 296
Зарегистрирован: 01.06.2012 14:54:10

Re: Как объявить процедурный тип для class ... static?

Сообщение alexs » 05.02.2015 09:18:59

А написать метод-обёртку над вызовом обращением к процедурной переменной? Заодно в нём можно проверки необходимые на корректность вызова добавить.
А саму процедурную переменную хранить в защищённой секции класса.
Аватара пользователя
alexs
долгожитель
 
Сообщения: 4060
Зарегистрирован: 15.05.2005 23:17:07
Откуда: г.Ставрополь

Re: Как объявить процедурный тип для class ... static?

Сообщение mgear » 05.02.2015 10:35:08

alexs, именно так сейчас и сделано. Судя по всему, так и останется.
mgear
новенький
 
Сообщения: 19
Зарегистрирован: 25.01.2015 19:29:56

След.

Вернуться в Общее

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

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

Рейтинг@Mail.ru
cron