Autor Beitrag
AndyB
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 1173
Erhaltene Danke: 14


RAD Studio XE2
BeitragVerfasst: Mo 28.08.06 22:12 
user profile icon2cHH hat folgendes geschrieben:
Du meinst, Delphi hat auch eine Möglichkeit, um Speicher zu allozieren
und freizugeben, die mit der von C kombatibel ist?

Das hängt davon ab, ob du gegen die msvcrtXX.dll (MSVC) / cp3245mt.dll (BDS 2006) linkst. In diesem Fall könntest du die free() Funktion importieren. Ansonsten hast du da wenig Changen (wie auch eine andere C++ DLL keine Change hätte)

_________________
Ist Zeit wirklich Geld?
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Mo 28.08.06 23:57 
user profile icon2cHH hat folgendes geschrieben:

Die DLL brauche ich ja wohl nicht wie in C mit "Bool FreeLibrary(ModuleHandle)"
wieder freizugeben, ich denke das wird Delphi schon machen, oder?

Im Prinzip nicht, aber wie neulisch schonmal jemand geschrieben hat: Du räumst dein Zimmer ja auch ab und zu mal auf. Im Idealfall nicht erst, wenn du ausziehst!
Bezogen auf den Fall: was du reservierst/anforderst/sonstwie erhältst, solltest du immer freigeben. Schon weil man vorher nie so genau weiß, ob wirklich alles von Delphi freigegeben wird.

Allerdings hat nicht mal Borland das so genau genommen, in der Graphics.pas ist auch ein Leck. TBitmap gibt irgendwas nicht richtig frei, weiß nicht mehr genau was. Das zeigt einem FastMM bei gesetztem Compilerschalter an. Ist schon interessant zu wissen, das auch Borland Fehler macht ;)


user profile icon2cHH hat folgendes geschrieben:
So langsam fängt Delphi an, Spass zu machen ;)

So ist Delphi nun mal :D

//Martok

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
2cHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46



BeitragVerfasst: Di 29.08.06 10:23 
user profile iconMartok hat folgendes geschrieben:
Bezogen auf den Fall: was du reservierst/anforderst/sonstwie erhältst, solltest du immer freigeben. Schon weil man vorher nie so genau weiß, ob wirklich alles von Delphi freigegeben wird.


Wird es ja, sobald das Programm beendet wird. ;)


Nein, Spass beiseite, ich habe mal etwas nachgefoscht, Delphi scheint die DLL nicht dynamisch nachzuladen, sondern gleich bei Programmstart. Das Nachladen ist wohl auch möglich (wie ich es verstanden habe), dann muss die DLL aber vorher auch explizit geladen werden.

Dynamisches Nachladen ist imho nur sinnvoll, wenn ein Programm länger läuft und dabei mehrere DLLs benutzt, die es aber nicht ständig braucht. Mein Programm braucht die DLL bei jedem Buttonklick und müsste die DLL dann jedesmal neu laden.

Ich habe das Programm auch mal in zwei Instanzen gestartet, die DLL wurde (laut Processexplorer) nur einmal geladen und von "beiden" Programmen benutzt. Genau so soll es meiner Meinung nach auch sein.




Aber bevor ich mich daran mache, die Funktion von C auf Delphi umzuschreiben, wollte ich nochmal sehen, ob ich den Speicher nicht von Delphi aus reservieren kann. So ähnlich wie es schon vorgeschlagen wurde, allerdings will ich erstmal nur den Zeiger auf den Speicher übergeben, keine boolschen Variablen.


Die DLL habe ich schon so umgeschrieben, dass sie als ersten Parameter den Zeiger auf den Puffer erwartet. Der Speicher wird in Delphi mit der Funktion GetMem reserviert, weil eine Initialisierung mit 0, wie sie durch AllocMem vorgenommen wird, nicht nötig wäre:


ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
var
  Form1: TForm1;
  sCont: PChar;
  pCont: ^Char;
  nSize: Integer;

implementation

{$R *.dfm}

Function MyReplace(sBuffer: PChar; sSource: PChar; sSearch: PChar; sReplace: PChar): PChar; StdCallexternal 'replaceDLL.dll' name 'strReplace';

procedure TForm1.Button1Click(Sender: TObject);
begin
sCont := PChar(RichEdit1.Text);
nSize := StrLen(sCont);
GetMem(pCont, nSize);
RichEdit1.Text := MyReplace(pCont,
                            sCont,
                            '1',
                            '2');
end;



Mein Problem ist jetzt, dass ich ^Char nicht als Typ für das Funktionsargument angeben kann (wird scheinbar nicht akzeptiert), aber PChar wohl nicht mit ^Char kompatibel ist.

Wie kann man den Zeiger auf den Puffer übergeben?



ps: die Fehlermeldung ist:

Zitat:
Incompatible types: 'Unit1.Char' and 'System.Char'
Motzi
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2931

XP Prof, Vista Business
D6, D2k5-D2k7 je Prof
BeitragVerfasst: Di 29.08.06 11:02 
Hi,

ich will an dieser Stelle nur einen kleinen Hinweis auf 2 meiner Tutorials absetzen. ;) Es handelt sich dabei um Tutorials zu den Themen "Pointer" und "Strings", beide speziell auf Delphi ausgerichtet. Da du sowohl mit dynamisch reserviertem Speicher als auch Strings/PChars und diversen Casts dazwischen arbeitest, könnten dir ein paar Tipps aus den Tutorials vermutlich noch ein bisschen bei der Optimierung weiterhelfen.

Gruß, Motzi

Edit: PChar ist zwar als ^char definiert, aber dennoch sind es für Delphi 2 verschiedene Typen (Delphi hat eben eine sehr strenge Typprüfung)! Du kannst das aber ganz einfach beheben indem du pCont als PChar deklarierst.

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Di 29.08.06 12:05 
Hm, mein Fehler. Ich hab nicht gesehen, dass du die DLL statisch einbindest. Ich hab DLLs eigentlich immer dynamisch, schon falls der User eine alte Version der DLL hat, die möglicherweise eine Funktion noch nicht enthält. Dann kann man das Programm wenigstens trotzdem starten. Das geht mit statisch eingebundenen nicht.

Aber wie dem auch sei: versuch doch mal eine Delphi-Portierung deiner Funktion. Ist gar nicht schwierig, sieht hinterher bloß anders aus ;)

//Martok

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
2cHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46



BeitragVerfasst: Di 29.08.06 14:50 
Hi,


ich habe jetzt die Speicherbelegung in Delphi hinbekommen:

ausblenden volle Höhe Delphi-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:
28:
29:
30:
31:
procedure TForm1.ButtonReplaceClick(Sender: TObject);

var
  pSource: PChar;
  pSearch: PChar;
  pReplace: PChar;
  pResult: PChar;
  nSource: Integer;
  nSearch: Integer;
  nReplace: Integer;
  nResult: Integer;

begin
  pSource := PChar(RichEditSource.Text);
  pSearch := PChar(RichEditSearch.Text);
  pReplace := PChar(RichEditReplace.Text);
  ;
  nSource := StrLen(pSource);
  nSearch := StrLen(pSearch);
  nReplace := StrLen(pReplace);
  ;
  if(nSearch > 0then
  begin
    nResult := (nSource div nSearch)* nReplace + nSource mod nSearch;
    if(nResult < nSource) then nResult := nSource;
    GetMem(pResult, nResult + 1);
    MyReplace(pResult, pSource, pSearch, pReplace);
    RichEditSource.Text := AnsiString(pResult);
    FreeMem(pResult);
  end;
end;



Funktioniert 1A mit der DLL. Jetzt habe ich mir überlegt, die gleiche Funktion in Delphi zu realisieren. Das String-Tutorial habe ich auch schon angefangen. Wenn es nachher um das optimieren des Delphi-Code geht, wird es mir bestimmt helfen.

Erstmal habe ich ohne Optimierung einfach versucht, die Funktion 1:1 zu übertragen. Dass dabei nicht das Maximum an Performance entstehen wird, ist klar. Das Übertragen allein ist aber auch ein gute Übung, weil ich dabei von C auf Delphi umdenken muss.


Ein paar Sachen lassen sich leider nicht so einfach wie in C realisieren, imho hat der Programmierer bei C mehr Freiheiten was z.B. Casts angeht. Die Typenstrenge hat bestimmt auch Vorteile, macht mir aber zur Zeit noch Probleme. ;)

ausblenden volle Höhe Delphi-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:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
procedure DelphiStrReplace(sBuff: PChar; sCont: PChar; sSearch: PChar; sRepl: PChar);
var
  nToCopy: Integer;
  pCont: PChar;
  pSearch: PChar;

begin
  if not (sSearch^ = '\0'then
  begin
    sBuff := sCont;
  end
  else
  begin
    //sBuff^ := '\0';//hier gibt es Troubles
    nToCopy := 0;
    while not (sCont^ = '\0'do
    begin
      if(sCont^ = sSearch^) then
      begin
        pCont := sCont;
        pSearch := sSearch;
        while(((++pCont)^ = (++pSearch)^) and (pCont^) and (pSearch^));//hier auch
        ;
        if(pSearch^ = '\0'then             //soweit ist der Compiler noch nicht gekommen
        begin
          strncat(sBuff, (sCont - nToCopy), nToCopy);
          nToCopy := 0;
          strcat(sBuff, sRepl);
          sCont += nSearch;
          continue;
        end;
      end;
      sCont++;
      nToCopy++;
    end;
    strncat(sBuff, (sCont - nToCopy), nToCopy);
  end;
end;



Eine Stringkonstante 'abc', ein Character 'a'. Soweit ich es verstanden habe. Problem ist jetzt aber der NullChar, der den String abschliesst '\0' sollte nicht als String, sondern als Char interpretiert werden.

Bin ich überhaupt auf dem richtigen Weg, lässt sich das ganze so wie in C realisieren?
Muss ich das continue z.B. durch ein Flag ersetzen?


Gruss aus Hamburg
mkinzler
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 4106
Erhaltene Danke: 13


Delphi 2010 Pro; Delphi.Prism 2011 pro
BeitragVerfasst: Di 29.08.06 15:01 
#0 statt '\0';
Inkrement per ++pCont geht auch nicht, selbiges gilt für sCont += nSearch;
du kannst PChar direkt durch Addieren weitercshieben

ausblenden Delphi-Quelltext
1:
2:
3:
p := PChar( 'ABC');
inc(p);
=> p := 'BC';

_________________
Markus Kinzler.
2cHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46



BeitragVerfasst: Di 29.08.06 20:57 
user profile iconmkinzler hat folgendes geschrieben:
#0 statt '\0';
ausblenden Delphi-Quelltext
1:
inc(p);					




thnx, ich hab's jetzt in Delphi hinbekommen:

*freu* :rofl:



ausblenden volle Höhe Delphi-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:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
procedure DelphiStrReplace(sBuff: PChar; sCont: PChar; sSearch: PChar; sRepl: PChar);

var
  pCont: PChar;
  pSearch: PChar;
  nToCopy: Integer;
  nSearch: Integer;

begin
  if (sSearch^ = #0then
  begin
    sBuff := sCont;
  end
  else
  begin
    sBuff^ := #0;
    nToCopy := 0;
    nSearch := StrLen(sSearch);
    while not (sCont^ = #0do
    begin
      if(sCont^ = sSearch^) then
      begin
        pCont := sCont;
        pSearch := sSearch;
        while( (pCont^ = pSearch^) and (not (pCont^ = #0)) and (not (pSearch^ = #0)) ) do
        begin
          inc(pCont);
          inc(pSearch);
        end;

        if(pSearch^ = #0then
        begin
          StrLCat(sBuff, (sCont - nToCopy), (StrLen(sBuff) + nToCopy));
          nToCopy := 0;
          StrCat(sBuff, sRepl);
          sCont := sCont + nSearch;
          continue;
        end;
      end;
      inc(sCont);
      inc(nToCopy);
    end;
    StrLCat(sBuff, (sCont - nToCopy), (StrLen(sBuff) + nToCopy));
  end;
end;


So sieht die direkte Portierung der Funktion aus der DLL aus. Leider erreicht sie nicht die Performance der DLL. Dass die Funktion in C etwas schneller ist, kann man wohl als normal betrachten, immerhin ist die DLL in reinem C geschrieben und auch so kompiliert, das ist imho (weil einfacher gestrickt) auch noch mal etwas schneller als C++.

Trotzdem glaube ich, dass aus der Implemantation in Delphi noch mehr rauszuholen ist, so dass sie noch dichter an die Funktion in C herannkommen kann. Das NonPlusUltra wäre meiner Meinung nach, durch Assemblerbefehle immer gleich 4 Chars auf einmal zu laden, aber so weit wollte ich bei meinem ersten Delphiprogramm nicht gehen.

Ich könnte mir vorstellen, dass StrCat und StrLCat zu langsam sind. Hinzu kommt noch, dass alle Längen vor der Aktion bekannt sind. StrCat und StrLCat müssen imho erst das NullChar finden, dann das NullChar entfernen, den Inhalt dazukopieren und dann das Nullchar wieder anhängen. Das tut hier eigentlich doch nicht Not, weil die Position vom NullChar mitgeführt werden kann.


Wenn ich nachdem gehe, was ich im Stringtutorial bis jetzt gelesen habe, was zugegeben noch nicht viel ist, könnte man auch einen Char-Array deklarieren.



Mal sehen, was am besten funktioniert.....

Gruss aus Hamburg
2cHH Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 46



BeitragVerfasst: Mi 30.08.06 00:54 
Ich habe jetzt die StrCat-Funktionen rasugeworfen und durch etwas schnelleres ersetzt:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
procedure MyStringPaste(nBuff: Integer; sBuff: PChar; sToPaste: PChar; nToPaste: Integer);

var
  nIndex: Integer;
  nCount: Integer;
  nLastPos: Integer;

begin
  nCount := 0;
  nLastPos := nBuff + nToPaste - 1;
  for nIndex := nBuff to nLastPos do
  begin
    sBuff[nIndex] := sToPaste[nCount];
    inc(nCount);
  end;
  sBuff[nIndex ] := #0;

end;


nBuff ist der OffSet im Puffer, von dem an geschrieben werden soll und wird von der Replace-Funktion als erster Parameter zusätzlich übergeben.

Das hat ganz schön was gebracht. ;)
Hätte ich nicht erwartet, wie schnell das jetzt schon läuft.


Damit ich das mal alles vergleichen kann, wie stelt man den Delphi-Compiler so ein, das er den schnellsten Code produziert?

Es gilt 16 MB Textersetzung (jedes zweite Zeichen) in ca. 3 sec zu schlagen.
(mehr konnte ich die Version mit DLL nicht verbessern)


Gruss aus Hamburg