| Autor |
Beitrag |
Atoll
Hält's aus hier
Beiträge: 9
|
Verfasst: Di 02.10.07 17:56
Hallo,
ich habe folgendes problem: ich moechte eine funktion aus einer c++ library verwenden. Die funktion hat ein struct (record in c++) als Parameter. Das Problem besteht darin das das struct ein Feld namens 'function' enthaelt und dieser Bezeichner von delphi bereits verwendet wird. Gibt es eine Moeglichkeit die dll funktion trotzdem zu verwenden?
Atoll
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Di 02.10.07 18:07
Das sind doch nur Bezeichner innerhalb deiner Programmsrache. Damit Delphi weiß auf welches Feld du zugreifen möchtest. Im echten Programm befinden sich keine Bezeichner mehr dort wird nur noch direkt auf den Speicherbereich zugeriffen.
Mit anderen Worten du kannst es "knoedeltroeten" nenne. Das juckt niemanden außer den der deinen Code lesen muss. 
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|
Atoll 
Hält's aus hier
Beiträge: 9
|
Verfasst: Mi 03.10.07 03:56
okay danke fuer die antwort.
es will allerdings immer noch nicht funktionieren. ich nehme anscheinend falsche typen.
Das hier ist der c++ typ einer funktion
C#-Quelltext 1: 2: 3: 4: 5: 6: 7:
| Data Type: gsl_function This data type defines a general function with parameters.
double (* function) (double x, void * params) this function should return the value f(x,params) for argument x and parameters params void * params a pointer to the parameters of the function |
diese funktion wird an eine andere funktion uebergeben:
C#-Quelltext 1: 2: 3:
| int gsl_integration_qags (const gsl_function * f, double a, double b, double epsabs, double epsrel, size t limit, gsl_integration workspace * workspace, double * result, double * abserr) |
bis auf die gsl_function habe ich alle typen ordentlich definiert in delphi. aber bei der gsl_function hapert es. wie wuerdet ihr die definieren?
Hier noch ein c++ beispielprogramm zu gsl_integration_qags:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
| #include <stdio.h> #include <math.h> #include <gsl/gsl_integration.h> double f (double x, void * params) { double alpha = *(double *) params; double f = log(alpha*x) / sqrt(x); return f; } int main (void) { gsl_integration_workspace * w = gsl_integration_workspace_alloc (1000); double result, error; double expected = -4.0; double alpha = 1.0; gsl_function F; F.function = &f; F.params = α gsl_integration_qags (&F, 0, 1, 0, 1e-7, 1000,w, &result, &error); printf ("result = % .18f\n", result); printf ("exact result = % .18f\n", expected); printf ("estimated error = % .18f\n", error); printf ("actual error = % .18f\n", result - expected); printf ("intervals = %d\n", w->size); return 0; } |
die DLL ist uebrigends die Gnu Scientific Library (libgsl)
Danke im vorraus
Atoll
Moderiert von Narses: Code- durch C#-Tags ersetzt
|
|
Stefan.Buchholtz
      
Beiträge: 612
WIN 2000, WIN XP, Mac OS X
D7 Enterprise, XCode, Eclipse, Ruby On Rails
|
Verfasst: Mi 03.10.07 11:07
Ok, gsl_function definiert also einen Zeiger auf eine Funktion, die einen double und einen untypisierten Pointer als Argumente bekommt und ein double zurückgibt.
Das sieht in Delphi so aus:
Delphi-Quelltext 1: 2:
| type TGslFunction = function(x: Double; params: Pointer): Double; stdcall; |
Die Funktion gs_integration_qags müsse dann so definiert werden:
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| function gsl_integration_qags(f: TGslFunction; a, b, epsabs, epsrel: Double; limit: Cardinal; workspace: PGslIntegration; var result: Double; var abserr: Double): Integer; stdcall; external 'libgsl.dll'; |
Bei limit bin ich mir aber nicht ganz sicher - ist size_t in C ein 32 Bit oder 64 Bit Typ?
Stefan
_________________ Ein Computer ohne Windows ist wie eine Schokoladentorte ohne Senf.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mi 03.10.07 20:01
u.U auch beachten, welches Speicheralignment benutzt wird.
Bei Dlphi kann man für einzelne Record-Typen das Alignment mit Packed Record abschalten.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Atoll 
Hält's aus hier
Beiträge: 9
|
Verfasst: Mi 03.10.07 20:30
Sollte GSL_function nicht eher von folgender struktur sein? :
Delphi-Quelltext 1: 2: 3: 4: 5: 6:
| type evalfunc = function(x:double; param:pointer):double; gslfunc = record func : ^evalfunc; params : pointer; end; |
zumindest ist Gsl_function in dem c++ beispielprogram ein record typ
Moderiert von Narses: Code- durch Delphi-Tags ersetzt
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Mi 03.10.07 21:56
Funktionspointer OHNE ^ vor'm Typbezeichner.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Atoll 
Hält's aus hier
Beiträge: 9
|
Verfasst: Do 04.10.07 03:58
Danke fuer die Hilfe, jetzt klappt es.
Falls jemand interesse hat die dll zu benutzen hier ein wenig code
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79:
| type
TGSLfunction = record func : function(x:double; params:pointer):double; CDECL; params : pointer; end;
TWorkspace = record limit : LongWord; size : LongWord; nrmax : LongWord; i : LongWord; maximum_level : LongWord; alist : Array of double; blist : Array of double; rlist : Array of double; elist : Array of double; order : Array of LongWord; level : Array of LongWord; end;
var
function mathfunction(x:double; params:pointer):double;CDECL;
function gsl_diff_central (f:pointer; x:double; result:pointer; abserr:pointer):integer;stdcall; external 'libgsl';
function gsl_integration_workspace_alloc (n:LongWord):pointer; CDECL; external 'libgsl';
function gsl_integration_qags(f: pointer; a, b, epsabs, epsrel: Double; limit: Cardinal; workspace: pointer; var result: Double; var abserr: Double): Integer; stdcall; external 'libgsl.dll';
procedure gsl_integration_workspace_free(w:pointer); CDECL; external 'libgsl';
...
function mathfunction(x:double; params:pointer):double; CDECL; var parameter:Array of double; begin Setlength(parameter,1); parameter := params; mathfunction := ln(parameter[0]*x) / sqrt(x); end;
procedure TSDIAppForm.Button2Click(Sender: TObject); var w:^TWorkspace; result,error : double; functest : TGSLfunction; parameters : Array of double;
begin Setlength(parameters,1); parameters[0]:=2; functest.func := mathfunction; functest.params := parameters;
gsl_diff_central (@functest, 4.0, @result, @error);
w:=gsl_integration_workspace_alloc(1000); gsl_integration_qags(@functest, 0, 1, 0, 0.0000001, 1000, w, result, error); gsl_integration_workspace_free(w);
label1.Caption:=floattostr(result); end; |
benutzt die funktionen zum integrieren und differenzieren aus der library
ich denke es ging vorher nicht da ich der mathfunction nicht CDECL nachgestellt hatte.
Atoll
Moderiert von Narses: Code- durch Delphi-Tags ersetzt
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Do 04.10.07 09:23
cdecl vs stdcall: Die Übergabe der Parameter bei stdcall und cdecl sind eigentlich gleich. Bei cdecl werden sie nur von dem wieder entsorgt der sie an die Funktion übergeben hat. Wenn du also eine cdelc funktion hast und diese als stdcall aufrufst bleiben unweigerliche Parammeter auf dem Stack liegen. Wenn diese funktionen sehr häufig aufgerufen werden läuft dir irgendwann der Stack voll. Überprüfe bitte GENAU welche Aufrufkonvention benutzt wird. Und setze diese dann einheitlich für alle deine Funktionen ein. Ich habe noch nie eine DLL gesehen bei der unetrschiedliche Konventionen gleichzeitig benutzt wurden.
TWorkspace: Bei den offenen Arrays handelt es sich normal nur um Pointer. Und wenn ich mich nicht vertue dann packt Delphi vor dem ersten Element noch die Größe mit in den Speicher. Wenn du also versuchst die Größe der Arrays abzufragen sollte es unweigerlich knallen, da C++ das höchstwahrscheinlich anders löst. (Das weiß ich nicht genau) Aber mit offen arrays wäre ich vorsichtig.
mathfunction: Da machst du etwas komisches. Du setzt die Länge eines arrays auf 1 und überschreibst es anschließend. Mich wundert es gerade, dass delphi das so ohne weiters schluckt. Aber für deinen Fall wäre wohl eher etwas wie folgendes das Bessere.
Delphi-Quelltext 1: 2: 3: 4:
| function mathfunction(x:double; params:pointer):double; CDECL; begin mathfunction := ln(pDouble(parameter)^ * x) / sqrt(x); end; |
Bzw dann genügt es auch wenn du den Pointer auf ein einfaches Double übergibst. Und wenn du ein Array brauchst dann solltest du den Parameter als pDoubleArray casten und das benutzen.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| type pDoubleArray = array of Double;
pDoubleArray(parameter)^[0] |
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|
Atoll 
Hält's aus hier
Beiträge: 9
|
Verfasst: Fr 05.10.07 00:56
bloede frage,
aber wo kann ich die aufrufkonvention CDECL oder stdcall anhand der library erkennen?
|
|
Lossy eX
      
Beiträge: 1048
Erhaltene Danke: 4
|
Verfasst: Fr 05.10.07 09:17
Diese Frage ich nicht blöd sondern bei C++ durchaus berechtigt. In Pascal steht die Konvention immer hinter der funktion. In C++ eher immer davor. Aber es wird eigentlich grundsätzlich immer per Präprozessor gelöst.
Als kleines Beispiel mal ein Ausschnitt aus einem Header von mir.
Quelltext 1: 2: 3: 4: 5: 6: 7:
| #define TSAPI __declspec(dllimport)
// diverse typdefinitionen
// viele viele Konstanten....
TSAPI tsBool tsInit (tsEnum Names); |
Wie du siehst steht bei der Methode noch das Define TSAPI davor. Der Präprozessor von C/C++ ersetzt das Define durch dessen Inhalt. __declspec(dllimport) bedeutet cdecl. Es gibt aber auch so etwas wie __cdecl das muss dann aber zwischen Rückgabewert und Methodennamen stehen. Bedeutet aber eigentlich das gleiche. Ansonsten gibt es noch so etwas wie __stdcall. Bzw gibt es noch das Standarddefine WINAPI was auch nur wieder auf __stdcall zeigt. Und wenn gar nichts angegeben ist dann sollte es auch stdcall sein. Aber das kann man sicherlich auch noch global in den Projekteinstellungen beinflussen. Also es gibt leider viel zu viele Möglichkeiten das einzustellen.
Aber es ist normal immer einheitlich in einer Library. Und spezielle Windows DLL sind eher stdcall wohingegen open source Bibliotheken eher cdecl benutzen. Da Linux normal mit cdecl arbeitet und man die dann der einfach heit auch so lässt.
Im Zweifel benutzt mal cdecl als Konvention. Da dadurch der Aufrufende die Paramater wegräumt werden im Falle einer stdcall methode die Parameter 2 mal weggeräumt und dabei zerschießt du dir recht schnell den Stack. Wenn also Fehler auftreten ist es vermutlich eine stdcall Methode. Wenn nicht und die methode auch arbeitet scheint es sich um cdecl zu handeln. Aber es ist logischerweise besser es vorher zu wissen. 
_________________ Nur die Menschheit ist arrogant genug, um zu glauben sie sei die einzige intelligente Lebensform im All. Wo nicht mal das nachhaltig bewiesen wurde.
|
|
|