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


Delphi4
BeitragVerfasst: Do 22.10.15 18:31 
Ein freundliches Hallo an alle,

ich möchte eine Struktur erstellen, die einen festen Teil (Head) und einen variablen Teil hat. In C kein Problem mit "Union".

In Delphi 4 habe ich einige Typen deklariert, die ich verwenden möchte.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
Type T_Typ = record
  Head : T_Head;
  case Integer of
    0 : (A : T_A);
    1 : (B : T_B);
    2 : (C : T_C);
    3 : (D : T_D);
  end;
end;


Ich erhalte die Fehlermeldung "Typ'T_A' benötigt Finalisation - nicht in varianten Record erlaubt".
Da ich die Typen wie "T_A" in Unterroutinen übergebe, aber nicht die gesamte Struktur möchte ich sie nicht 2 mal deklarierten. Hat Jemand einen Tipp??

Grüße von der dunklen Nordsee

Peter

Moderiert von user profile iconMartok: Titel korrigiert: Unit->Union
SMO
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 120
Erhaltene Danke: 18


D2005 Personal
BeitragVerfasst: Do 22.10.15 18:44 
Das sollte eigentlich so deklariert sein (kein "end" für das "case"):

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
Type T_Typ = record
  Head : T_Head;
  case Integer of
    0 : (A : T_A);
    1 : (B : T_B);
    2 : (C : T_C);
    3 : (D : T_D);
end;


Dein Typ T_A benutzt dynamische Arrays (dazu gehören auch Strings), wenn er Finalisation benötigt.
Du kannst ja mal die Definition von T_A zeigen, oder selbst darüber nachdenken, wie du dort ohne dynamische Arrays/Strings auskommen könntest.
Ansonsten bleibt dir nur, T_A aus der Union rauszunehmen.
Dynamische Arrays benötigen in Delphi nun mal Compiler-Magic (was sie komfortabler macht als C), der Compiler kann aber nicht wissen, ob die Union gerade T_A oder T_B enthält, also ob er den Speicher des dynamischen Arrays/Strings nun freigeben muss oder nicht, wenn die Lebenszeit des Records endet.
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Do 22.10.15 20:05 
Hallo SMO,

dank Dir für Deine Antwort. Die Strukturen enthalten Strings, Stringlisten und Stringgrids und sollen zum Einlesen von Daten verwendet werden. Damit alles über einen Aufruf läuft, hatte ich mir diesen Weg überlegt. Da diese Objelte durch einen Pointer repräsentiert werden war ich guter Dinge.

Grüße von der Nordsee

Peter
GuaAck
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 376
Erhaltene Danke: 32

Windows 8.1
Delphi 10.4 Comm. Edition
BeitragVerfasst: Do 22.10.15 21:30 
Hallo Peter18,

was auf jeden Fall gehen sollte:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
Type T_Typ = record
  Head : T_Head;
  case Integer of
    0 : (A : ^T_A);
    1 : (B : ^T_B);
    2 : (C : ^T_C);
    3 : (D : ^T_D);
end;

Die Zuweisungen müssten dann per "A := @T_A_Variable" erfolgen.

Eine schöne Lösung ist das nicht, der Compiler gibt eine Warnung aus, weil er nicht prüfen kann, ob die Typen passen; man muss also sorgfälltig sein. ("A := @T_B_Variable" würde der Compiler auch schlucken, mit Warnung.)

Gruß GuaAck
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Fr 23.10.15 11:20 
Hallo GuaAck,

auch Dir Dank für Deine Antwort. Werd ich mal ausprobieren. Als noch in Assembler programmiert wurde, mußte man auch selbst auf diese Dinge achten. Wenn einem zu viel abgenommen wird, ist es manchmal sehr unübersichtlich (Siehe Word). Wenn ich die Informationen über die Quelldatei und deren Daten vereinheitlichen kann, geht es vielleicht auch anders, mal sehen.

Grüße von der sonnigen Nordsee

Peter
Sinspin
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1321
Erhaltene Danke: 117

Win 10
RIO, CE, Lazarus
BeitragVerfasst: So 25.10.15 17:00 
Hallo Peter,

was spricht dagegen Dich garnicht erst mit so unübersichtlichen Strukturen zu befassen und alles in eine Klasse zu packen? So kannst Du auch gleich die Methoden fürs lesen, schreiben und eventuellen Konvertierungen mit unterbringen.

Unions sind schon eine feine Sache wenn man zb. einen Integer in einzelne Bytes oder Bits zerlegen will ohne jedesmal mit Masken oder Shifts arbeiten zu wollen.
Aber bei komplexen Datenstukturen ist es besser sich vorher genau zu überlegen ob man es mit einem bisschen mehr Aufwand doch vieleicht viel besser umsetzen kann indem man es in klassen packt.

_________________
Wir zerstören die Natur und Wälder der Erde. Wir töten wilde Tiere für Trophäen. Wir produzieren Lebewesen als Massenware um sie nach wenigen Monaten zu töten. Warum sollte unser aller Mutter, die Natur, nicht die gleichen Rechte haben?
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Mo 26.10.15 11:19 
Hallo Stefan,

dank für Deine Antwort. Die Unions wollte ich verwenden um eine einfache Schnittstele zu bauen, über die ich unterschiedliche Daten lesen und schreiben kann. Da die Informationen, die dazu notwendig sind sich sehr stark unterscheiden und zum Teil recht viel Speicher benötigen, wollte ich nur die Strukturen übergeben, die notwendig sind.

Nun habe ich schon alles entsprechend umgebaut. Ein Problem habe ich aber noch!

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
Type T_Typ = record
  Head : T_Head;
  case Integer of
    0 : (A : ^T_A);
    1 : (B : ^T_B);
    2 : (C : ^T_C);
    3 : (D : ^T_D);
end;

Das funktioniert soweit, aber wenn ich "A" oder "B" an eine Routine übergeben will meckert der Compiler. (Mal wieder Pointer) Je nach Daten soll eine Routine nur die benötigte Struktur erhalten, also etwa "F1( S.A );" oder "F2( S.B );". Auch "S.A^" mißfällt ihm.

Gibt es einen Trick?

Grüße von der sonnigen Nordsee bei 10°C

Peter

PS. wie ist das Wetter bei Dir?
SMO
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 120
Erhaltene Danke: 18


D2005 Personal
BeitragVerfasst: Mo 26.10.15 13:12 
Wie sind denn "F1" und "F2" definiert?

Wenn es "F1(A: T_A)" ist, dann sollte ein Aufruf wie "F1(S.A^)" funktionieren (wenn S: T_Typ). Falls nicht, sag mal die Fehlermeldung.
Falls die Subroutine die Felder des Records nur liest und keine Änderungen in den Record schreibt, dann ist es übrigens effizienter, "const" zu benutzen: F1(const A: T_A)
Wenn Felder geändert werden müssen und die Änderungen auch außerhalb sichtbar werden sollen, dann natürlich F1(var A: T_A).

Wenn du explizit Pointer an Subroutinen übergeben willst, musst du einen Pointertyp deklarieren:
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:
Type
P_A = ^T_A;
P_B = ^T_B;
P_C = ^T_C;
P_D = ^T_D;

T_Typ = record
  Head : T_Head;
  case Integer of
    0 : (A : P_A);
    1 : (B : P_B);
    2 : (C : P_C);
    3 : (D : P_D);
end;

procedure F1(A: P_A);
begin
  ...
end;

procedure F2(B: P_B);
begin
  ...
end;


Wie hier schon geschrieben wurde, besonders schön ist das nicht. Es gibt bestimmt sauberere Lösungen für deine Problemstellung. Aber ohne alle Details zu kennen, kann man keine konkreten Ratschläge geben.
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Mo 26.10.15 13:27 
Hallo SMO,

Dank Die für Deine Antwort! Da fällt es mir wie Schuppen aus den Haaren! Hätte ich eigentlich wissen sollen!

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
Type
P_A = ^T_A;
P_B = ^T_B;
P_C = ^T_C;
P_D = ^T_D;

hab ich nicht deklariert. Probier ich mal. ==> Alles klar!!!

Grüße von der noch immer sonnigen Nordsee bei 12°C

Peter
Blup
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 173
Erhaltene Danke: 43



BeitragVerfasst: Mo 26.10.15 15:16 
Sobald man mit Pointern arbeitet, sind die Daten nicht mehr im Speicherbereich des Record enthalten.
Teil des Record ist nur die Speicheradresse, unter der die Daten abgelegt sind.
Die Daten selbst müssen also irgendwo anders gespeichert sein.
Diese Punkte sind wichtig:
- wo wird der Speicher für die Daten bereitgestellt
- wo wird der Speicher wieder freigegeben

Im Prinzip ist auch diese Deklaration ausreichend:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
T_Typ = record
  Head: T_Head;
  P: Pointer;
end;