Rekursiver CallProc

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Mathias
Beiträge: 6906
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Rekursiver CallProc

Beitrag von Mathias »

Ich stehe an, weil ich ein C-Programm umsetzen wollte. In diesem hat es eine CallProc Function, welche man Rekursiv aufrufen muss.
Ich dachte ich hätte dies schon mal, aber bei genaueren betrachten habe ich gesehen, das es dazumal eine procedure war. Und im jetztigen Programm eine function.

Daher habe ich diesen Test geschrieben und muss festellen, das es mit procedure geht, aber mit function hat der Compiler Mühe.

Es kommt folgender Fehler:

Code: Alles auswählen

project1.lpr(24,19) Error: Incompatible type for arg no. 1: Got "Pointer", expected "<procedure variable type of function(LongInt):LongInt;CDecl>"
Kann man dies umgehen, oder habe ich einen Überlegungsfehler ?

Oder geht dies mit FPC einfach nicht ?

Code: Alles auswählen

program project1;

type
  TProc = procedure(i: integer); cdecl;
  TFunc = function(i: integer): integer; cdecl;

  procedure InitProc(fn: TProc);
  begin
    // Ist in einer C-Lib
  end;

  procedure InitFunc(fn: TFunc);
  begin
    // Ist in einer C-Lib
  end;

  procedure proc(i: integer); cdecl;
  begin
    InitProc(@proc);
  end;

  function func(i: integer): integer; cdecl;
  begin
    InitFunc(@func); // geht nicht, Fehlermeldung
  end;

begin
  InitProc(@proc);
  InitFunc(@func);
end.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: Rekursiver CallProc

Beitrag von MmVisual »

Bei

function func(i: integer): integer;

gibt es ja auch kein Return-Wert.

Mache mal das dazu:
Result := 0;

Und wenn die rekursive Schleife nicht irgend wann mal unterbrochen wird ist irgendwann auch mal der Stack voll und das Programm kann dann nur noch beendet werden.

Das Schlüsselwort "Implementation" fehlt.
Und deklarieren "func" dann im Deklarationsteil, damit müsste der Compiller das wissen,
EleLa - Elektronik Lagerverwaltung - www.elela.de

Mathias
Beiträge: 6906
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Rekursiver CallProc

Beitrag von Mathias »

Mache mal das dazu:
Result := 0;
Dies ist mir schon bewusst, ich habe es auf ein Minimum abgespeckt.
Und wenn die rekursive Schleife nicht irgend wann mal unterbrochen wird ist irgendwann auch mal der Stack voll und das Programm kann dann nur noch beendet werden.
Bei dem ganzen handelt es sich um eine Timer Funktion in einer C-Lib, welche ich durch InitFunc und initProc ersetzt habe.
Das Schlüsselwort "Implementation" fehlt.
Seit wann braucht es implementation im Hauptprogramm, dies braucht es nur in einer Unit.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

MmVisual
Beiträge: 1581
Registriert: Fr 10. Okt 2008, 23:54
OS, Lazarus, FPC: Winuxarm (L 4 FPC 3.2.2)
CPU-Target: 32/64Bit

Re: Rekursiver CallProc

Beitrag von MmVisual »

Ich habe den verdacht (nicht jetzt getestet), dass wenn man eine Funktion nutzen möchte diese vorher bekannt sein muss.
Klar im Programm kann man eine Funktion nutzen, ohne diese vorher zu deklarieren. Allerdings muss man dann die Reihenfolge der Funktionen im Quelltext einhalten. Und da die Funktion sich selbst aufruft müsste diese also vorher deklariert sein (wäre zumindest denkbar).

Ich würde im Code alle Warnungen und Hints raus programmieren, nicht dass die Kombination daraus im Compiller eine falsche Meldung aus gibt. Daher der Hinweis wegen "Result".
EleLa - Elektronik Lagerverwaltung - www.elela.de

Mathias
Beiträge: 6906
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Rekursiver CallProc

Beitrag von Mathias »

Ich habe den verdacht (nicht jetzt getestet), dass wenn man eine Funktion nutzen möchte diese vorher bekannt sein muss.
Dies wäre etwas komisch. Dann würde sich die procedure gleich verhalten wie die function.
Mit procedure gehr es ja.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
Zvoni
Beiträge: 368
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz 2.2.2 FPC 3.2.2)
CPU-Target: 32Bit
Wohnort: BW

Re: Rekursiver CallProc

Beitrag von Zvoni »

Huh? Ziemlich skurril....
Das hier compiliert

Code: Alles auswählen

program project1;
{$mode objfpc}{$H+}
type
  TProc = procedure(i: integer); cdecl;
  TFunc = function(i: integer): integer; cdecl;

  procedure InitProc(fn: TProc);
  begin
    // Ist in einer C-Lib
  end;

  procedure InitFunc(fn: TFunc);
  begin
    // Ist in einer C-Lib
  end;

  procedure proc(i: integer); cdecl;
  begin
    InitProc(@proc);
  end;

  function func(i: integer): integer; cdecl;
  begin
    InitFunc(TFunc(func)); // <---- "@" ersetzt mit "TFunc"-Cast
  end;

begin
  InitProc(@proc);
  InitFunc(@func);  //Das hier wird aber nicht angemotzt
end.
Ein System sie alle zu knechten, ein Code sie alle zu finden,
Eine IDE sie ins Dunkel zu treiben, und an das Framework ewig zu binden,
Im Lande Redmond, wo die Windows drohn.

Mathias
Beiträge: 6906
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Rekursiver CallProc

Beitrag von Mathias »

Bei mir geht dies nicht. Egal ob mit oder ohne. {$mode objfpc}{$H+}

Code: Alles auswählen

  function func(i: integer): integer; cdecl;
  begin
    InitFunc(TFunc(func)); // <---- "@" ersetzt mit "TFunc"-Cast
  end;
So kompiliert er es:

Code: Alles auswählen

InitFunc(TFunc(@func));

Ich habe das ganze noch ein wenig abgeändert:

Code: Alles auswählen

program project1;
type
  TProc = procedure(i: integer); cdecl;
  PProc=^TProc;
  TFunc = function(i: integer): integer; cdecl;
  PFunc=^TFunc;

  procedure InitProc(fn: TProc);
  const
    i:Integer=0;
  begin
    // Ist in einer C-Lib

    WriteLn('Proc ',i);
    Inc(i);
    fn(i);
  end;

  procedure InitFunc(fn: TFunc);
  const
    i:Integer=0;
  begin
    // Ist in einer C-Lib

    WriteLn('Func ',i);
    Inc(i);
    fn(i);
  end;

  procedure proc(i: integer); cdecl;
  begin
    InitProc(@proc);
  end;

  function func(i: integer): integer; cdecl;
  begin
//    InitFunc(@func); // geht nicht
    InitFunc(TFunc(@func));
    Result:=0;
  end;

begin
  InitProc(@proc);
//  InitFunc(@func);
end.
Starte ich das gabze mit InitProc(@proc); geht der Zähler auf etwas 130'000 und dann überläuft wie erwartet der Stack.
Starte ich mit InitFunc(@func); geht der Zähler auf 2 und dann SIGSEV 216.


So nebenbei habe ich in meinem original Programm bei der C-Bindund die function durch procedure ersetzt, dann läuft es. Es ist ein Timer der alle Sekunde durchläuft. Aber sauber wird dies nicht sein, da die procedure ein Result zurück geben kann.

Das original C-Demo sieht so aus:

In der main.c

Code: Alles auswählen

static int on_timer(Tickit *t, TickitEventFlags flags, void *_info, void *user);
static int on_timer(Tickit *t, TickitEventFlags flags, void *_info, void *user)
{
  int *counterp = user;

  (*counterp)++;
  tickit_window_expose(timerwin, NULL);

  tickit_watch_timer_after_msec(t, 1000, 0, &on_timer, user);

  return 0;
}
Im Header:

Code: Alles auswählen

typedef int TickitCallbackFn(Tickit *t, TickitEventFlags flags, void *info, void *user);
...
void *tickit_watch_timer_after_msec(Tickit *t, int msec, TickitBindFlags flags, TickitCallbackFn *fn, void *user);
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten