Autor Beitrag
DelphiNoob
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 152

Win 2003 Server
D7 Ent
BeitragVerfasst: So 23.03.03 12:26 
Hi,

ich will nen Shortstring in ein TListitem Data Feld packen! Der ist aber Pointer, und ne umwandlung von ShortString nach Pointer geht ja nicht wirklich.

Wäre nett wenn mir jemand kompatible Typen nenne könnte. Im Shortstring steht übrigens immer eine IP Adresse, vieleicht ist das ja hilfreich zu wissen.

Mfg
DelphiNoob
SMI
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 106

Win95-2003 / Debian / Suse
D1/D3/D6/D7
BeitragVerfasst: So 23.03.03 14:15 
Prinzipiell müssten folgende Zeilen helfen.

STRING -> POINTER;
* Zuerst wird genügend Speicher reserviert Stringlänge +1 Zeichen
* Danach wird der String in einen Pointer Of Char umgewandelt
* und schließlich der Pointer zurückgegeben

POINTER -> STRING;
* Mithilfe von dem Cast STRING(PCHAR(pointer)) wandelt man den
Pointer in einen PChar um und dann schließlich ein einen String;

WICHTIG !!!
* Die Länge des Strings kann nicht mehr verändert werden!
* Man muss den Pointer nach Gebrauch per Hand freigeben !
Darüberhinaus sollte man ihn noch mit NIL ins Nirvana schicken
* Der Code ist "Quick & Dirty" als es findet keine Fehler
Überprüfung statt!


SMI

ausblenden 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:
VAR
  pp :Pointer;

Function ShortStringToPointer(s:String): Pointer;
VAR
 p : PCHAR;
BEGIN
 GetMem(p,length(s)+1);
 StrPCopy(p,s);
 result:= POINTER(p);
END;

procedure TForm1.Button1Click(Sender: TObject);
VAR
 str: string[20];
begin
 str:= 'TEST';
 pp := NIL;
 pp := ShortStringToPointer(str);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 showmessage('|'+STRING(PCHAR(pp))+'|');
 freemem(pp);   // WICHTIG !!!!
 pp:= NIL
end;

_________________
Wenn es im Jahre 1879 schon Computer gegeben hätte, würden diese vorausgesagt haben, daß man infolge der Zunahme von Pferdewagen im Jahre 1979 im Pferdemist ersticken würde.
(John C. Edwards, brit. Zukunftsforscher)


Zuletzt bearbeitet von SMI am So 23.03.03 14:27, insgesamt 1-mal bearbeitet
DelphiNoob Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 152

Win 2003 Server
D7 Ent
BeitragVerfasst: So 23.03.03 14:19 
Danke! Sehr nett erklärt.
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mo 24.03.03 15:43 
Hi!

Eine IP-Adresse? Dann brauchst du gar keinen Shortstring, sondern nur ein Integer. Die Pointer-Variable ist ja genau 32 Bit groß, nimmt also genau den Platz ein, den du für eine IP-Adresse benötigst. Das kannst du einfach mit
"ListItem.Data=Pointer(IPAdress);" zuweisen.

Du musst nur zwei Routinen schreiben die die Umwandlung erledigen, also :
function StrToIP(Str:String):Integer;
function IPToStr(IP:Integer):String;

Die gibt es bestimmt schon irgendwo vorgefertigt.

Cu,
Udontknow
DelphiNoob Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 152

Win 2003 Server
D7 Ent
BeitragVerfasst: Mo 24.03.03 16:19 
Also du meinst wenn die IP Adresse Integer ist, kann ich einfach: Listitem.Data := Pointer(MeinString); machen?

Muss ich da nicht noch groß ne Function schreiben für Pointer()?

Weil den Ursprünglichen String einfach in einen Integer zu wandeln ist ja kein Problem.
DelphiNoob Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 152

Win 2003 Server
D7 Ent
BeitragVerfasst: Mo 24.03.03 16:32 
Ich hab das mal ausprobiert, aber er sagt klipp und klar das ne IP Adresse kein gültiger Integer Wert ist. Irgendwie auch klar, weil ich sehe "255.255.255.255" auch nicht als Zahl an. Allein schon wegen den vielen Punkten. Also irgendwie muss man da doch was machen können.
DelphiNoob Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 152

Win 2003 Server
D7 Ent
BeitragVerfasst: Mo 24.03.03 16:56 
OK ERLEDIGT!

Habs auf ne etwas andere art gelöst, indem ich den String umwandle! Aber es funzt jetzt!

DANKE
SMI
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 106

Win95-2003 / Debian / Suse
D1/D3/D6/D7
BeitragVerfasst: Mo 24.03.03 20:26 
@Udontknow

ListItem.Data:=Pointer(IPAdress); ist brand gefährlich müsste zudem auch nicht tun, denn du übergibst einen Pointer der auf den Inhalt von IPAdresse zeigt, desweiteren sollten Pointer Speicherplätze sollten gar nie(!) Zweckentfremdet werden. Das kann sehr böse ins Auge gehen. Man weiß nie wie die der übergebene Pointer intern benutzt wird, es kann/könnte zu sporadischen nicht definierbaren abstürzen, sowie zu Datenverlust kommen! Daher setzt man auch Pointer immer zu NIL wenn man sie nicht mehr braucht! Ich kann dazu nur sagen, das Pointer Anfänger vieleicht reizen aber um damit umgehen zukönnen muss man viele Feinheiten wissen, und dass brauch jahrelange Programmiererfahrung!


@All

IP -> INTEGER;
* Zuerst werden 4 Bytes ( entspricht einem Integer) reserviert
* nun wird dem golbalen Pointer of Byte pAscii dir adresse der IP String übergeben.
* NextTriple zerlegt die Tripel einer IP.
* Tripel (1byte lang) wird nun in pByte gespeichert.
* und der Zeiger von pByte um eins erhöht
* selbisges geschieht noch 3 Mal
* Danach wird der Zeiger wieder um 3 zurück geschoben
* pByte übergibt seine Adresse einem Pointer of Integer
* selbiger wid nun derefenziert und übergibt seinen Inhalt an die Funktion

NextTriple
* Rückgabe Wert wird genullt
* Wenn das aktuelle Byte vom String IP dem einem Punkt (Ascii Wert 46 ) entspricht winr die Position im String um eins erhöht
* Solange die Schleife ungleich der Binären 0 oder einem Punkt ist
* wird die Variable result um eine Stelle erhöht
* der Asciiwert des aktuellen Zeichen - dem Zeichen '0' (48) in result addiert.
* Danach wird die Position im String um eins erhöht

Bemerbung:
ausblenden Quelltext
1:
2:
3:
// "Ascii" Table
// 46 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57
//  . |  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9

String 172 entspricht der Ascii Folge 49|55|50 man könnte sie aber auch so darstellen 49-48=1|55-48=7|50-48=2


INTEGER -> IP;
* Die Adresse des Integers wid dem Pointer of Char übergeben
* Das erste Byte des Intergers wird gelesen und in einen String umgewandelt.
* der Pointer wird um eins erhöht
* selbiges geschieht noch drei mal

WICHTIG !!!
* Es findet keine Fehler überprüfung, d.h. statt übergibt man den funktionen Schrott wird es einen bösen Absturz geben!
* Die Funktion NextTriple greift auf die Variable der Funktion IpToInt zurück!

BEISPIEL

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
procedure TForm1.Button1Click(Sender: TObject);
VAR
 ip : integer;

BEGIN
 ip := IpToInt('172.20.0.1');
 Showmessage(IntToStr(ip));
 showmessage(IntToIp(IP));
END;


CODE:


ausblenden volle Höhe 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:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
FUNCTION IpToInt(IP:String): Integer;
VAR
  pAscii : ^Byte;

FUNCTION NextTriple : BYTE;
BEGIN
 result:=0;
 IF (pAscii^=46)  THEN INC(pAscii);
 WHILE (pAscii^<> 0) AND (pAscii^<>46) DO
 BEGIN
  result:=result *10;
  result:= Result + (pAscii^ -48);
  INC(pAscii);
 END;
END;

VAR
 pByte: ^Byte;
 iIp : ^Integer;
 testInt :Integer;
begin
 GetMem(pByte, 4);
 pAscii:=POINTER(IP);
 pByte^:= NextTriple;
 INC(pByte,1);
 pByte^:= NextTriple;
 INC(pByte,1);
 pByte^:= NextTriple;
 INC(pByte,1);
 pByte^:= NextTriple;
 DEC(pByte,3);

 iIP:=POINTER(pByte);
 result:=iIP^;
 FreeMem(pByte);
end;

FUNCTION IntToIp(Ip:Integer): STRING;
VAR
 pByte: ^Byte;
begin

 pByte := @IP;
 // Delphi castet INTEGER nicht zu einem typ geringerer
 // genauigkeit ohne Schutzverletzunggecastet werden
 // daher müssen wird via @ explizit nur die Adresse übergeben.
 // Hier würde POINTER(IP) würde zu einer schutzverletzung führen!!!

 result:=IntToStr(pByte^)+'.';
 INC(pByte);
 result:=Result + IntToStr(pByte^)+'.';
 INC(pByte);
 result:=Result + IntToStr(pByte^)+'.';
 INC(pByte);
 result:=Result + IntToStr(pByte^);
end;

_________________
Wenn es im Jahre 1879 schon Computer gegeben hätte, würden diese vorausgesagt haben, daß man infolge der Zunahme von Pferdewagen im Jahre 1979 im Pferdemist ersticken würde.
(John C. Edwards, brit. Zukunftsforscher)
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Mo 24.03.03 21:37 
@SMI:

Naja, also als Anfänger würde ich mich nicht gerade bezeichnen. Ich habe da schon so einige Jahre auf dem Buckel... Kommen wir mal zum Thema:

Die Zweckentfremdung ist in keinster Weise brandgefährlich, ich mache es sehr häufig so. Ohne Fehler. Du hast da, glaube ich, ein Verständnis-Problem, was Typenkonvertierung angeht.

Zitat:
denn du übergibst einen Pointer der auf den Inhalt von IPAdresse zeigt,


Nein, das ist falsch. Ich übergebe den Integer-Wert einer IP-Adresse als Pointer. Pointer(Integerwert) gibt nicht einen Zeiger auf den Integerwert zurück, sondern den Integerwert als Zeiger.
Wenn ich den Wert wieder abgreifen will konvertiere ich einfach in die andere Richtung: Ich hole den Wert des Pointers und konvertiere ihn zu Integer.

Deshalb kann es auch gar nicht zu Datenverlust kommen. Weder reserviere ich dynamisch Speicher, noch ändere ich irgendwelche Adressen von Variablenzeigern. Es ist schlicht und ergreifend nur eine Typkonvertierung. :)

Genau das gleiche macht übrigens die Funktion Ptr:

Zitat:
function Ptr(Address: Integer): Pointer;

In Delphi konvertiert Ptr die mit Address angegebene Adresse in einen Zeiger. Durch einen Aufruf dieser Funktion wird kein Quelltext erzeugt, der angegebene 32-Bit-Wert wird einfach als Zeiger behandelt. Wie NIL ist der Rückgabewert von Ptr zu allen Zeigertypen zuweisungskompatibel.


Was deine Routinen angeht:
Du machst es dir meiner Meinung nach unnötig schwer, indem du hier Speicher reservierst, da ein wenig mit der Ascii-Tabelle herumfummelst, und eine wahre Orgie mit Referenzierung und Dereferenzierung veranstaltest. Das kann früher oder später nur Chaos geben. Delphi hat doch IntToStr-beziehungsweise StrToInt-Routinen, warum denn mühselig alles selber zusammenrechnen?

Hier mal meine, wie ich finde, übersichtlicheren Routinen:

ausblenden volle Höhe 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:
function StrToIP(Str:String):Integer;
var B:Array[0..3] of Byte;
var i,DotPos:integer;
var StrPart:String;
begin
  //Dummypunkt zum Parsen hinzufügen
  Str:=Str+'.';
  //Alle 4 8Bit-Werte ermitteln
  for i:=0 to 3 do
  begin
    //Position des nächsten Punkts ermitteln
    Dotpos:=Pos('.',Str);
    //Chars bis zum nächsten Punkt ermitteln
    StrPart:=Copy(Str,1,DotPos-1);
    //Alles bis zum nächsten Punkt aus Str ausschneiden
    Str:=Copy(Str,DotPos+1,255);
    //Byte-Wert ermitteln
    B[i]:=StrToInt(StrPart);
  end;

  //Integer aus den Bytes zusammenstellen
  Result:=B[3];
  for i:=2 downto 0 do
    Result:=Result shl 8 +B[i];
end;

function IPToStr(IP:Integer):String;
var B:Byte;
var i:integer;
begin
  Result:='';
  //Sämtliche Bytes durchgehen
  for i:=0 to 3 do
  begin
    //Speicherstelle des Integers byteweise abtasten
    B:=Byte(Pointer(Integer(Addr(IP))+i)^);
    //Byte als Str zum Resultat hinzufügen
    Result:=Result+IntToStr(B);
    if i<3 then
      Result:=Result+'.';
  end;
end;

Cu,
Udontknow
SMI
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 106

Win95-2003 / Debian / Suse
D1/D3/D6/D7
BeitragVerfasst: Di 25.03.03 04:12 
@Udontknow

Du hattest mich da falsch verstanden. Als erstes die Warnung für Anfänger war nicht an dich gerichtet sondern an die Allgemeinheit. Desweitern ist das Problem wo es zu Datenverlust kommen kann, folgendes du weist dem Pointer Speicherplatz TListItem.Data eine " Fake" Adresse. Diese Adresse ist wie du ja beschrieben hattest keine reale Adresse, sondern nur ein als Integer mißbrauchter Pointer, der igendwohin zeigt. Weißt au aber was ListItem intern mitdiesem Pointer macht? Wie sieht es mit zukünftigen Windows Versionen aus? Was ist wenn in einer zukünftigen Windowsversion überprüft wird, ob der Pointer überhaupt zulässig ist. Denn er kann genausogut auf einen geschützten Speicherbereich zeigen, das würde eine nicht deutbare Schutzverletzung geben. Des weiteren könnet Listbox selber den Pointer in einer ähnlich Art und Weise mißbrauchen, oder eine verrsteckte Funktion zur Speicherfreigabe, die bei Fehlern eingreift haben.
Genau das sind die Gründe, warum man Pointer nur als Zeiger verwenden sollte, und nicht als Datenspeicher mißbraucht!

Mit einem muss dir Wohl oder Übel rechtgeben mein Ausführung zu ListItem.Data:=Pointer(IPAdress), dass war und ist ein Denkfehler gewesen und somit Schlichtweg falsch. Zu meiner Verteidigung: Ich habe die Benutzung von Casts und Pointer nicht in Pascal gelernt sonder in C/C++.

Delphi TypeCasts sind eh was besonderes Delphi überprüft intern irgendwie ihre Gültigkeit, oder kanst du mir sagen wie folgendes nur mit einer Typumwandlung ohne zusätzlichen reservierten Speicher funktioniert. Ich wandele einen lokalen String via Cast in einen Pointer um, was an sich ja garnicht gehen kann und darf, da ein Pointer ja nur 4 Bytes speichern kann und mein String eindeutig größer ist. Nun ändere ich meinen String. Wenn ich nun in einer anderen Funktion den Pointer wieder in einen String Caste erhalte ich keine Schutzverletzung sonder den kompletten Stringwert wieder zurück. Warum geht das gut?

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
VAR
 p:pointer;

procedure TForm1.Button1Click(Sender: TObject);
VAR
 str : String;
 int : integer;
begin
 str := 'TEST TEST TEST TEST TEST TEST TEST TEST';
 p:= POINTER(str);
 Str:='1234';
 showmessage(str);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 Showmessage(STRING(p));
end;


Zu dem Thema "Was deine Routinen angeht":

Bei der Routine bin ich etwas anderer Meinung. Der Programmieraufwand war für beides Codes sicherlich gleich groß, ich glaube nicht, dass du merklich weniger Zeit als ich dazu gebraucht hast.
Zugegeben deiner sieht optisch übersichtlicher aus, jedoch viel besser lesbar ist er dadurch auch nicht geworden.
Hingegen ist die Performance meines Codes eindeutig wesentlich besser. Bei der ersten Funktion verwendest du einen String zum Zwischenspeichern, eine langsame for Schleife. Du greifst auf jeden Stringeintrag etwa 3 bis 4 mal zu, zuerst via pos, danach zwei mal via Copy und zuletzt nochmal mit StrToInt. Meine Routine verwendet eine schelle While Schleife und greift auf jeden String Eintrag genau einmal zu!
Die andere Funktion ist eigentlich exakt identisch. Mit dem Unterschied, das ich vollkommen ohne if Abfrage und For Schleife, Zählvariable und Abbruchbedingung auskomme, was eindeutig auch der Übersichtlichkeit dient.
Bei einem Projekt musste ich schonmal "schmerzhaft" feststellen, dass eine einzige "optimierte" Methode Stunden Rechenzeit sparen kann. Daher habe ich es mir angewöhnt alles mit möglichst geringen Schritten, möglichst Effektiv zu programmieren. Was sich bisher eigentlich immer ausgezahlt hat, daher kann ich es nur empfehlen.

Das ich eine "wahre Orgie mit Referenzierung und Dereferenzierung veranstalte" ist auch eine Erbsünde aus der C/C++ Programierung.
Aber dass daraus ein Chaos entsteht möchte ich bezweifeln, ansonsten wären deiner Theorie nach jegliches C/C++ Projekt zum scheitern verurteilt. Nur zur Erinnerung Windows und Linux basieren eigentlich nur auf C/C++ Code der mit Pointer nur so um sich schmeist.

SMI

Moderiert von user profile iconUGrohne: Code-Tags eingefügt

_________________
Wenn es im Jahre 1879 schon Computer gegeben hätte, würden diese vorausgesagt haben, daß man infolge der Zunahme von Pferdewagen im Jahre 1979 im Pferdemist ersticken würde.
(John C. Edwards, brit. Zukunftsforscher)
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 25.03.03 07:50 
SMI hat folgendes geschrieben:
Delphi TypeCasts sind eh was besonderes Delphi überprüft intern irgendwie ihre Gültigkeit, oder kanst du mir sagen wie folgendes nur mit einer Typumwandlung ohne zusätzlichen reservierten Speicher funktioniert. Ich wandele einen lokalen String via Cast in einen Pointer um, was an sich ja garnicht gehen kann und darf, da ein Pointer ja nur 4 Bytes speichern kann und mein String eindeutig größer ist. Nun ändere ich meinen String. Wenn ich nun in einer anderen Funktion den Pointer wieder in einen String Caste erhalte ich keine Schutzverletzung sonder den kompletten Stringwert wieder zurück. Warum geht das gut?

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
VAR
 p:pointer;

procedure TForm1.Button1Click(Sender: TObject);
VAR
 str : String;
 int : integer;
begin
 str := 'TEST TEST TEST TEST TEST TEST TEST TEST';
 p:= POINTER(str);
 Str:='1234';
 showmessage(str);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 Showmessage(STRING(p));
end;


Also was die TypeCasts angeht kann ich auch mal meinen Senf dazu geben...

Der normale Variablen-Typ String ist (sofern nicht per Projektoptionen oder Compiler-Schalter anders angegeben) nur ein Pointer. Ein String ist einem PChar gar nicht so unähnlich. Er zeigt auf eine Speicherstelle an der die Zeichenkette abgelegt ist, und genauso wie auch beim PChar wird das Ende mit einem Nullzeichen gekennzeichnet. Hier endet aber auch schon die Ähnlichkeit. Delphi verwendet nämlich intern noch eine Länge und einen Referenzzähler (beides 32Bit Integer) welche VOR der eigentlichen Zeichenkette stehen (also praktisch ein negatives Offset haben). Der TypeCast Pointer(String) gibt also eigentlich nur einen Pointer auf das erste Zeichen zurück. Das kann man auch ganz einfach zeigen wenn man dein Beispiel erweitert:
ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
VAR
 str: String;
 p: Pointer
begin
 str := 'TEST TEST TEST TEST TEST TEST TEST TEST';
 p:= Pointer(str);
 ShowMessage(str);
 ShowMessage(PChar(p));

 PChar(p) := 'blablabla'
 ShowMessage(str);
 ShowMessage(PChar(p));
end;


Eine weitere Möglichkeit einen String in einen PChar zu konvertieren ist ein direkter TypeCast PChar(String) oder @String[1]. Je nach Methode führt Delphi intern jedoch verschiedene mappings aus.

Mehr Informationen dazu findest du hier: www.delphipraxis.net/viewtopic.php?t=1188

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Di 25.03.03 08:33 
Korrekt @ Motzi.

@SMI:

Du hast natürlich recht, wenn du sagst, daß so ein missbrauchter Pointer dann auf einen Speicherbereich zeigt, der nicht unbedingt initialisiert ist. Aber das ist tatsächlich egal, denn die Benutzung dieser Pointer liegt allein in der Hand des Entwicklers (siehe Hilfe Zu TListItem.Data). Niemals gibt eine (Standard-)Komponente einfach mal irgendeinen Speicherbereich frei, oder führt eine Operation darauf aus. Und da MS immer Wert auf Abwärtskompatibiltät legt, werden sie auch keine versteckte Betriebssystem-Funktion einschleusen, die so etwas macht. Es stellt sich die Frage, ob ein Betriebssystem überhaupt erkennen kann, was ein Pointer ist und was nicht. :)

Ein weiteres schönes Beispiel für das reibungslose Ablaufen von Typenkonvertierung, das ich häufig einsetze, ist TIntegerList. Du kannst sehr einfach eine Klasse TIntegerlist stricken, die einfach anstelle von Zeigern Integerwerte speichert (jetzt rate mal, wie :wink: ).

Hier mal der Code:

ausblenden volle Höhe 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:
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:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
unit Integerlist;

// Unit mit der Klasse TIntegerlist, einer Liste von Integerwerten (Oh, wirklich??? ;) )

interface

uses classes;

type TIntegerList= class(TObject)
  private
    FList:TList;
    function GetItems(Index: Integer): Integer;
    procedure SetItems(Index: Integer; const Value: Integer);
  public
    procedure LoadFromStream(Stream:TStream); virtual;
    procedure SaveToStream(Stream:TStream); virtual;
    function Count:Integer;
    procedure Clear;
    function Add(Value:Integer):Integer;
    function IndexByValue(Value:Integer):Integer;
    property Items[Index:Integer]:Integer read GetItems write SetItems; default;
    constructor Create;
    destructor Destroy; override;
end;

implementation

{ TIntegerList }

function TIntegerList.Add(Value: Integer): Integer;
begin
  Result:=FList.Add(Pointer(Value));
end;

procedure TIntegerList.Clear;
begin
  FList.Clear;
end;

function TIntegerList.Count: Integer;
begin
  Result:=FList.Count;
end;

constructor TIntegerList.Create;
begin
  FList:=TList.Create;
end;

destructor TIntegerList.Destroy;
begin
  FList.Free;
  inherited;
end;

function TIntegerList.GetItems(Index: Integer): Integer;
begin
  Result:=Integer(FList.Items[Index]);
end;

function TIntegerList.IndexByValue(Value: Integer): Integer;
var i:integer;
begin
  Result:=-1;
  for i:=0 to Self.Count-1 do
    if Self[i]=Value then
    begin
      Result:=i;
      exit;
    end;
end;

procedure TIntegerList.LoadFromStream(Stream: TStream);
var Count:Integer;
var i,Value:integer;
begin
  Self.Clear;
  Stream.ReadBuffer(Count,SizeOf(Count));
  for i:=0 to Count-1 do
  begin
    Stream.ReadBuffer(Value,SizeOf(Value));
    Self.Add(Value);
  end;
end;

procedure TIntegerList.SaveToStream(Stream: TStream);
var Count:Integer;
var i,Value:integer;
begin
  Count:=Self.Count;
  Stream.WriteBuffer(Count,SizeOf(Count));
  for i:=0 to Count-1 do
  begin
    Value:=Self[i];
    Stream.WriteBuffer(Value,SizeOf(Value));
  end;
end;

procedure TIntegerList.SetItems(Index: Integer; const Value: Integer);
begin
  FList.Items[Index]:=Pointer(Value);
end;


end.
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 25.03.03 13:56 
@Udontknow: Die Idee hat was! Simpel aber effektiv! :D
Ich hatte vor mir in den nächsten Tagen auch eine Integer-Liste zu schreiben, aber jetzt.. hast du was dagegen wenn ich mir den Code "ausborge"?

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
Luckie
Ehemaliges Mitglied
Erhaltene Danke: 1



BeitragVerfasst: Di 25.03.03 13:59 
Infos findet man auch noch hier: www.optimalcode.com/string.htm
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Di 25.03.03 15:37 
@Motzi:

Klar kannst du, dafür habe ich ihn ja gepostet. Ein kleines "ThxTo" wäre alles, wenn du damit groß an die Öffentlichkeit willst... :)

Cu,
Udontknow
SMI
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 106

Win95-2003 / Debian / Suse
D1/D3/D6/D7
BeitragVerfasst: Di 25.03.03 17:00 
@Luckie

Danke.


@Udontknow

Zitat:
Aber das ist tatsächlich egal, denn die Benutzung dieser Pointer liegt allein in der Hand des Entwicklers (siehe Hilfe Zu TListItem.Data)


In Hilfen kann viel stehen, genauso in Dokumentationen, aber hast du den Quellcode dazu gesehen? Da Microsoft ihn nicht rausrückt, weißt du also nicht, ob irgendo in TListItem.Data eine "versteckte" Freigabe steht. Besonders in der WinApi gibt es viele Befehle die sich entgegen der offiziellen Dokumentation verhalten.
Aber Prinzipiell ist es dein Problem, es ist nur so eine Sache wie mit dem Label und Goto Befehlen, sie existiern einwand frei, aber man sollte sie einfach nicht nicht verwenden!

SMI

_________________
Wenn es im Jahre 1879 schon Computer gegeben hätte, würden diese vorausgesagt haben, daß man infolge der Zunahme von Pferdewagen im Jahre 1979 im Pferdemist ersticken würde.
(John C. Edwards, brit. Zukunftsforscher)
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 25.03.03 17:27 
Udontknow hat folgendes geschrieben:
@Motzi:

Klar kannst du, dafür habe ich ihn ja gepostet.

Dankeschön! :)
Zitat:
Ein kleines "ThxTo" wäre alles, wenn du damit groß an die Öffentlichkeit willst... :)

Aber selbstverfreilicht! :wink: Bist somit in der AboutBox meines X-Spys verewigt! :) Wenn du willst kann auch dein richtiger Name rein...

_________________
gringo pussy cats - eef i see you i will pull your tail out by eets roots!
Udontknow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2596

Win7
D2006 WIN32, .NET (C#)
BeitragVerfasst: Di 25.03.03 19:35 
@SMI: Es ist irgendwie müssig, über so etwas zu diskutieren. Es steht nunmal in der Hilfe, und wenn es nicht so wäre, wie es dort steht, würde Borland bereits viele recht zornige Kommentare bekommen haben.
Wenn man sich auf gar nichts verlassen will, darf man gar nicht erst mit dem Programmieren anfangen. Und wie ich bereits sagte, ich bezweifle, dass das Betriebssystem erkennen kann, wie ein Programm bestimmte Speicherbereiche nutzt.

Cu,
Udontknow