StringList zu C-StrArray umwandeln

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 7347
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

StringList zu C-StrArray umwandeln

Beitrag von af0815 »

Ich habe ein Problem mit dem Umwandeln von einer Stringliste zu einem StringArray ür eine C Bibliothek (libgit2).

Die Definition des Stringarrays in C ist folgendermassen
Original aus der strarray.h

Code: Alles auswählen

/** Array of strings */
typedef struct git_strarray {
	char **strings;
	size_t count;
} git_strarray;
Überstezt nach Pascal in

Code: Alles auswählen

(** Array of strings  *)

type
  git_strarray = record
    strings: PPAnsiChar;
    Count: size_t;
  end;
  Pgit_strarray = ^git_strarray;


meine Umsetzung mittels

Code: Alles auswählen

procedure StringListToGitStrArray(const List: TStringList; out Arr: git_strarray);
var
  i: Integer;
  S: AnsiString;
  Len: SizeUInt;
  P: PPAnsiChar;
begin
  Arr.Count := List.Count;

  if Arr.Count = 0 then
  begin
    Arr.strings := nil;
    Exit;
  end;

  GetMem(Arr.strings, Arr.Count * SizeOf(PAnsiChar));
  P := Arr.strings;
  for i := 0 to Arr.Count - 1 do
  begin
    S := UTF8Encode(List[i])+#0;   // für Git besser
    Len := Length(S);

    GetMem(P^, Len);

    if Len > 0 then
      Move(Pointer(S)^, P^, Len);
    Inc(P);
  end;
end;  
hakt, ich bekomme immer einen GPF (bin unter Linux) in der lib. Aktuell such ich mir einen Wolf und vermute, das ich ganz einfach Betriebsblind bin. Und so ein Pointerfreak bin ich auch nicht. Da habe ich sicher etwas vermurkst, nur sehe ich es nicht.

BTW: Lazarus/FPC main zeigt mir soger die Stellen im C-Code an, da ich die Sourcen von libgit2 am Rechner habe.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 7347
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: StringList zu C-StrArray umwandeln

Beitrag von af0815 »

Irgendwie hat das Forum auch Probleme, nach dem Editieren ist alles weg, mit der Meldung das der Beitrag nicht existiert.

Neuer (pascalischer) Ansatz:

Code: Alles auswählen

procedure StringListToGitStrArray(const SL: TStringList; out GitArray: git_strarray);
var
  I: Integer;
  PArray: PPAnsiChar;
begin
  GitArray.Count := SL.Count;

  if GitArray.Count = 0 then
  begin
    GitArray.strings := nil;
    Exit;
  end;

  PArray := GetMem(GitArray.Count * SizeOf(PAnsiChar));
  GitArray.strings := PArray;

  for I := 0 to SL.Count-1 do
  begin
    PArray[I] := StrNew(PAnsiChar(AnsiString(SL[I])));
  end;
end;
Sieht einmal besser aus. GPF weg.
Das das Programm noch nicht das macht was ich will, ist eine andere Geschichte.

Edit: Jetzt ist Theo Beitrag weg - dewegen vielleicht die Fehlermeldung und alles aus dem Editor verschwunden.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
theo
Beiträge: 11354
Registriert: Mo 11. Sep 2006, 19:01

Re: StringList zu C-StrArray umwandeln

Beitrag von theo »

Sry, hatte meinen Beitrag gelöscht, weil er Käse war. :oops:
War kurz verwirrt, aufgrund deines AnsiChar.
Das "Ansi" kannst du dir sparen, ist alles dasselbe.

Code: Alles auswählen

  AnsiChar            = Char;
  PAnsiChar           = PChar;
  PPAnsiChar          = PPChar;
  PPPAnsiChar         = PPPChar;    
Ich hüpfe jetzt mal in den See, vielleicht wird's dann besser. :lol:

Benutzeravatar
Zvoni
Beiträge: 700
Registriert: Fr 5. Jul 2024, 08:26
OS, Lazarus, FPC: Windoof 10 Pro (Laz/FPC fixes)
CPU-Target: 64Bit
Wohnort: BW

Re: StringList zu C-StrArray umwandeln

Beitrag von Zvoni »

Code: Alles auswählen

program Project1;
{$mode ObjFPC}{$H+}
Uses Sysutils, classes;
type
  git_strarray = record
    strings: PPAnsiChar;
    Count: size_t;
  end;
  Pgit_strarray = ^git_strarray;
Var
  SL:TstringList;
  gsa:git_strarray;
  x:Integer;
  P:PPAnsiChar;
procedure StringListToGitStrArray(const List: TStringList; out Arr: git_strarray);
var
  i: Integer;
  S: AnsiString;
  Len: SizeUInt;
begin
  Arr.Count := List.Count;
  if Arr.Count = 0 then
  begin
    Arr.strings := nil;
    Exit;
  end;
  GetMem(Arr.strings, Arr.Count * SizeOf(PAnsiChar));
  for i := 0 to Arr.Count - 1 do
  begin
    S := UTF8Encode(List[i]);   // für Git besser
    Len := Length(S);
    if Len > 0 then
    Begin
      New(Arr.Strings[i]);
      Move(PAnsiChar(s)^,Arr.Strings[i]^,Len+1);
    end;
  end;
End;
begin
  SL:=TStringList.Create;
  SL.Add('Eintrag 1');
  SL.Add('Eintrag 2');
  SL.Add('Eintrag 3');
  SL.Add('Eintrag 4');
  SL.Add('Eintrag 5');
  StringListToGitStrArray(SL,gsa);
  P:=@gsa.strings[0]; //Zeiger auf Anfang der Liste
  For X:=0 To gsa.Count-1 Do
    Begin
      Writeln('Iteration Index: '+gsa.strings[x]);
    end;
  Writeln('----------------------------');
  For x:=0 To gsa.count-1 Do
    Begin
      Writeln('Iteration Zeiger: '+p^);
      Inc(p);
    end;
  Readln;
end.
Kein Anspruch auf Expertentum!! :D :D
Und ja: Das Ding leckt wie ne kaputte Heizung.
War ich jetzt zu faul :D
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.

Benutzeravatar
theo
Beiträge: 11354
Registriert: Mo 11. Sep 2006, 19:01

Re: StringList zu C-StrArray umwandeln

Beitrag von theo »

Zvoni hat geschrieben: Fr 19. Jun 2026, 11:33 Und ja: Das Ding leckt wie ne kaputte Heizung.
Naja, wenn man nichts freigibt... :lol:

Ich hab's mal so angepasst. Scheint zu funzen und heaptrace ist auch happy.
Aber vllt. wird das in AF's Fall vom C code freigegeben.

Code: Alles auswählen

procedure StringListToGitStrArray(const List: TStringList; out Arr: git_strarray);
var
  i: Integer;
  S: AnsiString;
  Len: SizeUInt;
begin
  Arr.Count := List.Count;
  if Arr.Count = 0 then
  begin
    Arr.strings := nil;
    Exit;
  end;
  GetMem(Arr.strings, Arr.Count * SizeOf(PAnsiChar));
  for i := 0 to Arr.Count - 1 do
  begin
    S := UTF8Encode(List[i]);   // für Git besser
    Len := Length(S);
    if Len > 0 then
    Begin
      Arr.Strings[i]:=StrAlloc(Len+1);
      Move(PAnsiChar(s)^,Arr.Strings[i]^,Len+1);
    end;
  end;
End;

procedure TForm1.Button1Click(Sender: TObject);
Var
  SL:TstringList;
  gsa:git_strarray;
  x:Integer;
  P:PPAnsiChar;
begin
    SL:=TStringList.Create;
    SL.Add('Eintrag 1');
    SL.Add('Eintrag 2');
    SL.Add('Eintrag 3');
    SL.Add('Eintrag 4');
    SL.Add('Eintrag 5');
    StringListToGitStrArray(SL,gsa);
    P:=@gsa.strings[0]; //Zeiger auf Anfang der Liste
    For X:=0 To gsa.Count-1 Do
      Begin
        Writeln('Iteration Index: '+gsa.strings[x]);
      end;
    Writeln('----------------------------');
    For x:=0 To gsa.count-1 Do
      Begin
        Writeln('Iteration Zeiger: '+p^);
        StrDispose(p^);
        Inc(p);
      end;
    Freemem(gsa.strings);
    SL.Free;
end;     

Warf
Beiträge: 2312
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: StringList zu C-StrArray umwandeln

Beitrag von Warf »

Grad nicht am PC zum testen, aber wenn man irgendwie an den internen raw pointer der StringList ran kommt kann man den einfach verwenden. Eine stringlist hat soweit ich weiß intern einfach einen continuous block von strings, die ja C String kompatibel sind.

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 7347
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: StringList zu C-StrArray umwandeln

Beitrag von af0815 »

Warf hat geschrieben: Fr 19. Jun 2026, 15:24 Grad nicht am PC zum testen, aber wenn man irgendwie an den internen raw pointer der StringList ran kommt kann man den einfach verwenden. Eine stringlist hat soweit ich weiß intern einfach einen continuous block von strings, die ja C String kompatibel sind.
Naja, ich bevorzuge einen Weg,, den ich auch noch morgen verstehe :-)
Und einfach ist es nicht, weil in der Struktur ja nur die Pointer auf die Strings hintereinander liegen, nicht die Strings.

Der zweite Ansatz schaut nicht schlecht aus und macht zumindest keinen GPF. Nachdem das kompilierte C-Beispiel auch nicht unbedingt das macht, was man erwartet, ist die jetzige Lösung mal ok.

Vor allen den Test von Zvoni muss ich mir noch einbauen um die Struktur besser debuggen zu können.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Warf
Beiträge: 2312
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: StringList zu C-StrArray umwandeln

Beitrag von Warf »

Hat halt den Nachteil das man die ganzen Daten einmal komplett kopieren muss. Je nachdem wie viel das ist kann das schon echt langsam sein und viel Speicher fressen.

Ich hab grade nochmal geschaut, mit TStringList geht es nicht, mit TVector allerdings schon:

Code: Alles auswählen

program Project1;

{$mode objfpc}{$H+}

uses
  heaptrc, gvector;

var
  v: specialize TVector<String>;
  r: record
    strings: PPAnsiChar;
    Count: SizeInt;
  end;
  i: Integer;
begin
  v:=specialize TVector<String>.Create;
  v.PushBack('Entry1');
  v.PushBack('Entry2');
  v.PushBack('Entry3');
  r.strings:=PPAnsiChar(v.Mutable[0]);
  r.Count:=v.Size;

  // Test ob die Daten auch korrekt sind
  for i:=0 to r.Count-1 do
    WriteLn(r.strings[i]);

  // Free'd auch die daten in r.Strings
  v.Free;
end. 

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 7347
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: StringList zu C-StrArray umwandeln

Beitrag von af0815 »

Danke,
die Doku zu TVektor liegt hier, falls sie wer sucht (oder am lokalen Rechner)
https://gitlab.com/freepascal.org/fpc/s ... c/main.pdf

Ich habe aber da noch einen anderen Fehler, den ich suchen muss. Der ist aber in den Demosourcen von Libgit2 selbst :-)
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: StringList zu C-StrArray umwandeln

Beitrag von Mathias »

Eine Warnung vor weg, ich habe gesehen, das ihr Speicher mit GetMem reserviert, diese PChar Array ist nicht voll kompatibel mit C.
Sobald man zB.

Code: Alles auswählen

GIT_EXTERN(void) git_strarray_dispose(git_strarray *array);
aufruft, dann knallt es.
GetMen und FreeMem ist nicht kompatibel zu den C malloc und free.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2312
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: StringList zu C-StrArray umwandeln

Beitrag von Warf »

Dafür kann man den C memory manager (unit cmem als erste unit in der lpr) einbinden. Dann nutzt getmem und freemem (sowie new und dispose) die libc Funktionen malloc und free

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 7347
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: StringList zu C-StrArray umwandeln

Beitrag von af0815 »

Gut zu wissen, nur soweit bin ich nicht. Bei der Lib, darf ich meine eigenen Sachen selbst zerstören, ANsonsten kannich das die Lib machen lassen, soweit ich bisher gekommen bin. Das vereinfacht die Sache, weil ich mich nicht um den Memory Manager kümmern muss.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

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

Re: StringList zu C-StrArray umwandeln

Beitrag von Mathias »

Warf hat geschrieben: Fr 19. Jun 2026, 17:40 Dafür kann man den C memory manager (unit cmem als erste unit in der lpr) einbinden. Dann nutzt getmem und freemem (sowie new und dispose) die libc Funktionen malloc und free
Ich habe mir gerade diese Unit angeguckt, für was baut die soviel overhead ein ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 2312
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: StringList zu C-StrArray umwandeln

Beitrag von Warf »

Zwei Dinge, zum einen C Kompatibilität, damit kann man Speicherallokationen einfach zwischen C und Pascal hin und her reichen und es ist egal wer sie erstellt und wer sie freed. Zum anderen ist der C Memory Manager verdammt schnell, somit kann man in diversen Scenarien einiges an Laufzeit rausholen gegenüber dem Pascal Memory Manager.

Antworten