Autor Beitrag
Peter18
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Sa 24.01.15 17:17 
Ein freundliches Hallo an alle,

ich war auf der Suche nach einer Function oder Procedure mit der Speicherbereiche kopiert werden können. Da ich in der Hilfe nichts passendes (außer StrCopy) mit dem ich eine Struktur in einen Speicherbereich kopieren kann, um sie dann einer Systemschnittstelle zu übergeben, habe ich gedacht ich könnte es auch selbst programmieren. Doch nicht mit Delphi!

Das Umkopieren ist notwendig, da dynamische Strukturen enthalten sind und ich sie einzeln anlegen und dann zusammenkopieren will. "Type Arr = Array of Byte;" erzeugt eine Zugriffsverletzung.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
Type Arr = Array of Byte;
Type P_A = ^Arr;

var
  SPtr  : P_A;     // Source-Pointer
  DPtr  : P_A;     // Destination-Pointer
... 
  PMsg := AllocMem( Msg.Length );
  SPtr := @Msg;
  DPtr := PMsg;
  for I := 0 to SizeOf( Msg ) - 1 do DPtr^[I] := SPtr^[I];

Daher die Frage (falls ich nach den falschen Stichworten gesucht habe) gibt es eine Function oder Procedure mit der diese Opperationen ausgeführt werden können oder wie muß das syntaktisch geschrieben werden?

Grüße von der Nordsee

Peter
mandras
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 429
Erhaltene Danke: 107

Win 10
Delphi 6 Prof, Delphi 10.4 Prof
BeitragVerfasst: Sa 24.01.15 17:20 
Ich denke, Du suchst die MOVE-Prozedur aus der Unit System.

Da fällt mir noch was ein bzgl. des Fehlers:

Ein Array of byte ist ein dynamisches Array und nicht das gleiche wie zB ein array [0 .. 100000] of byte. Mit letzterem sollte Dein Beispiel funktionieren.
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Sa 24.01.15 19:17 
Evtl. auch CopyMemory
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: Sa 24.01.15 22:15 
Das sollte so aussehen


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:
23:
24:
25:
// Typendeklarationen immer T<name>
// bitte leg keinen Pointer auf ein dynamisches Array an, wenn du nicht 100% weißt was du da tust
// wenn du unbedingt GetMem verwenden willst dann besser nur mit "x: Pointer" oder "x: PByte" etc.
type
  TArr = array of Byte;
var
  x, y: TArr;
  i: integer;
begin
  // Speicher reservieren (fuer dynamische Arrays bzw. Strings)
  SetLength(x, 10);

  // x -> 1..10
  for i := Low(x) to High(x) do
    x[i] := i+1;

  // kopie anlegen, bei "y := x"  würde Y nur eine Referenz sein
  y := Copy(x);

  // 1. Wert in Y aendern (low(x) entspricht bei dynamische Arrays "0")
  y[Low(y)] := 99;

  Caption := Format('%d %d', [x[low(x)], y[Low(y)]]);
  // mit @x[Low(x)] bzw @x[0] erhaelt man die Adresse auf das 1. Byte
end;

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: So 25.01.15 12:55 
Hallo mandras, hallo WasWeißDennIch, hallo uall@ogc,

Dank euch für die Antworten. Alle sind sehr nützlich. Mit der Krücke "array [0 .. 100000] of byte" funktioniert es. Ist aber etwas unbefriedigend, eine vernünftige Pointerarithmetik (wie in C) würde einiges vereinfachen! Die Routinen "MOVE" und "CopyMemory" sind genau das, was ich in der Hilfe gesucht aber nicht gefunden habe. Auch mit den richtigen Stichworten erscheint dort nichts, dafür nochmals danke. "CopyMemory" scheint in diesem Fall die bessere Wahl zu sein, da ich hier Pointer übergeben kann (wegen anhängen weiterer Daten).
Zitat:
// kopie anlegen, bei "y := x" würde Y nur eine Referenz sein

Kann ich bestätigen, das Ergebnis sah aus wie ein Array of Pointer. "y := Copy(x);" ist ein guter Hinweis! Na ja, Pascal war ja eigentlich als Sprache für Schulungen gedacht.

Grüße von der Nordsee

Peter
mandras
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 429
Erhaltene Danke: 107

Win 10
Delphi 6 Prof, Delphi 10.4 Prof
BeitragVerfasst: So 25.01.15 14:22 
Da muß ich doch noch was anmerken..

M.M. nach ist gerade das Fehlen einer Pointerarithmetik in Delphi ein großer Vorteil.

In Einzelfällen, besonders bei der Verwendung von System-APIs, könnte Pointerbehandlung wie in C etwas vereinfachen.
Dennoch sind die Gefahren beträchtlich.
uall@ogc
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1826
Erhaltene Danke: 11

Win 2000 & VMware
Delphi 3 Prof, Delphi 7 Prof
BeitragVerfasst: So 25.01.15 19:57 
Hallo Peter,
Delphi nimmt die einen großen Teil des Aufwandes ab. Natürlich kannst du auch ein dynamsiches Array verwenden und muss nicht die Krücke "array [0 .. 100000] of byte" nehmen.
Dafür musst du aber den Unterschied verstehen.
Bei einem statischen Array ist zur Compilerzeit bekannt wie groß dieses Array ist, und es hat immer mindestens einen Eintrag [0..0].

D.h. @StatischesArray und @StatischesArray[0] das gleiche.

Bei dynamischen Arrays ist das aber anders aus, da du die Länge ja zur Laufzeit verändern kannst (SetLength).
Daher sind @DynamischesArray und @DynamischesArray[0] unterschiedliche Dinge.

@DynamischesArray ist ein Zeiger auf das Array (PPointer). 4 Bytes vor jedem dynamischen Array steht die Länge.
@DynamischesArray[0] zeigt auf das 1. Element (das was du haben willst).

Wenn du also Speicher in ein dynamisches Array kopieren willst kannst du das am besten so machen:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
type
  TData = array of TStruct;
var
  a: TData;
begin
  SetLength(a, 10); // 10 Elemente des Typs TStruct
  
  // ... 
  if Length(a) > 0 then begin
    // bei dynamischen Arrays sollte das immer geprueft werden,
    //die Länge könnte 0 sein und beim Zugriff auf das 1. Element gibt es eine AccessViolation (nicht in dem Beipiel)

    CopyMemory(@a[Low(a)], srcpointer, Length(a) * SizeOf(a[Low(a)])); // SizeOf(a[0]) NICHT SizeOf(a) !!!
  end;



Hier sieht du den Unterschied zwischen @DynArr und @DynArr[0]

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
type
  TStruct = record
    a: Integer;
    b: Integer;
  end;
var
  arr: array of TStruct;
begin
  SetLength(arr, 3);
  Caption := Format('%x %d %x' ,[
    Integer(PPointer(@arr)^),                        // entspricht @arr[0]
    Integer(PInteger(Integer(PPointer(@arr)^)-4)^),  // Length(arr)
    Integer(@arr[0])
    ]);


Natürlich solltest du nicht auf das Array bzw. die Länge wie im obigen Beispiel zugreifen.
Sondern "Length", "SetLength", "@Arr[Low(Arr)]" etc. nutzen.

Delphi nimmt dir halt einen großen Teil ab, so kann man ganz einfach das dynamische Array vergrößern:

ausblenden Delphi-Quelltext
1:
SetLength(a, Length(a)+1);					


Delphi reserviert den Speicher automatisch und kopiert die Elemente um, wenn dies nötig ist.
Außerdem musst du dich bei dynamischen Arrays nicht darum sorgen wann der Speicher wieder freigegeben werden soll (FreeMem etc.)

Wenn du länger mit Delphi arbeitest wirst du schon die Vorzüge von kennen lernen :)

Wenn du einzelne Records kopieren willst geht das auch über das dereferenzieren:

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
type
  TStruct = record
    a: Integer;
    b: Integer;
  end;
  PStruct = ^TStruct;
var
  x, y: TStruct;
  z: PStruct;
begin
  x.a := 1;
  x.b := 1;

  z := @x;

  /// du bekomsmt z.b. z von extern übergeben (API) und willst davon eine Kopie in y haben:
  
  y := z^; // Daten werden automatisch kopiert

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit


Zuletzt bearbeitet von uall@ogc am So 25.01.15 19:58, insgesamt 1-mal bearbeitet

Für diesen Beitrag haben gedankt: Nersgatt
OlafSt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Mo 26.01.15 13:37 
Das Problem in unserem Fall ist allerdings, das die API-Strukturen eine unterschiedliche Länge haben. Sicherlich nehmen einem dynnamsiche Arrays ne Menge Arbeit ab. Aber das einfache umkopieren eines PCHAR z.B. geht rasch in die Hose.

Die strenge Typprüfung mag für C-Programmierer ein echtes Problem darstellen. Aber das ist auch nur ein Zeichen dafür, welchen haarsträubenden Irrsinn man in C veranstalten kann. So kann man, ohne irgendeine Fehlermeldung, den schon genannten PCHAR irgendwohin kopieren. Bis es dann irgendwann später mal kracht, wenn man den PCHAR dereferenziert und man nicht erkennt, das der mal auf dem Stack lag - womöglich merkt man das erst Tage später.

Man muß sich in Delphi also bei solchen Problemen deutlich mehr Gedanken über die Details machen. Dafür hat man die Mühe aber beim Programmieren, nicht erst mit dreifachem Zeitaufwand beim Debuggen. Ist man dann auch noch relativ neu in Delphi, glaubt man rasch eine "blöde" Sprache zu benutzen.

In C# sind solche Zeigergeschichten übrigens nur noch mit erheblichem Aufwand und dutzenden Compilerwarnungen machbar. In Visual Basic geht sowas IIRC gar nicht mehr.

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
SMO
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 120
Erhaltene Danke: 18


D2005 Personal
BeitragVerfasst: Mo 16.02.15 16:13 
user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Na ja, Pascal war ja eigentlich als Sprache für Schulungen gedacht.


Was sollen diese plumpen Seitenhiebe? Ein modernes Delphi hat einen weit größeren Funktionsumfang als das Ur-Pascal und wurde definitiv nicht für Schulungen konzipiert.
Pointerarithmetik geht in Delphi auch problemlos, jedenfalls in neueren Versionen. Wenn du tatsächlich noch mit Delphi 4 herumdümpelst, könnte das ein Problem sein.
Ein weiteres Problem von dir scheint auch zu sein, dass du die Sprache einfach nicht gut genug kennst (Unterschied von statischen und dynamischen Arrays, Existenz von Move).


Zuletzt bearbeitet von SMO am Mo 16.02.15 18:08, insgesamt 1-mal bearbeitet
OlafSt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Mo 16.02.15 17:45 
Warum denn gleich so aggressiv ?

Selbstverständlich war Pascal als Sprache für den Unterricht konzipiert. Nicht umsonst war Pascal jahrelang die alles beherrschende Programmiersprache an Schulen und Unis. Allerdings ist es richtig, Object Pascal von heute ist doch erheblich verändert, besonders im Hinblick auf OOP (das Mitte der 80er Jahre erst aufkam) und den neuesten Entwicklungen in der Softwareentwicklung, wie Generics u.a.

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.