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


Delphi4
BeitragVerfasst: Mi 21.01.15 17:29 
Ein freundliches Hallo an alle,

in der Hilfe steht, dass man mit Pointern auch rechnen kann. Doch mir gelingt es nicht! Immer wenn ich einen Pointer auf etwas zeigen lasse, z.B. eine Struktur von einem Systemaufruf und möchte einen neuen Pointer mit Offset in die Struktur zeigen lassen, kommt eine Fehlermeldung.

Beispiel:
Eine Systemnachricht hat einen Kopf, aus dem hervorgeht, wie der Rest der Nachricht zu interpretieren ist. Auf Grund der Information aus dem Header möchte ich einen Pointer der passenden Struktur auf diesen Teil setzen.

Also so etwas: PInfo := PMessage + SizeOf( Header );

Hat jemand ein Syntax-Beispiel???

Grüße von der Nordsee

Peter
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: Mi 21.01.15 21:16 
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
PInfo := Pointer(Integer(PMessage) + SizeOf(Header))

oder

PInfo := PInfo(Integer(PMessage) + SizeOf(Header))

_________________
wer andern eine grube gräbt hat ein grubengrabgerät
- oder einfach zu viel zeit
Tastaro
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 414
Erhaltene Danke: 23



BeitragVerfasst: Do 22.01.15 09:58 
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Do 22.01.15 12:27 
Hallo uall@ogc, hallo Tastaro,

Dank euch für eure Antworten. Niklaus Wirth sei's gedankt, dass solche Sachen nicht so einfach sind wie in "C". Doch viele seiner Gedanken sind bereits aufgeweicht worden (Exit, Goto, Peek, Poke u.s.w.).

Die Krücke der Typumwandlung habe ich auch schon gefunden. Doch die Hilfe gaukelt die Möglichkeit der direkten Pointerarithmetik vor:
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:
Die relationalen Operatoren <, >, <= und >= können Operanden vom Typ PChar haben (siehe den
Abschnitt Relationale Operatoren). Bei den folgenden Operatoren können die Operanden auch Zeiger sein.
Ausführlichere Informationen über Zeiger finden Sie im Abschnitt Zeiger und Zeigertypen.

Operator  Operation  Operandtyp  Ergebnistyp  Beispiel
+  Zeiger-Addition  Zeichenzeiger, Integer   Zeichenzeiger  P + I 
-  Zeiger-Subtraktion  Zeichenzeiger, Integer  Zeichenzeiger, Integer  P - Q 
^  Zeiger-Dereferenzierung  Zeiger   Basistyp von Zeiger  P^
=  Gleichheit   Zeiger   Boolean  P = Q 
<>  Ungleichheit  Zeiger  Boolean   P <> Q 
Der Operator ^ dereferenziert einen Zeiger. Sein Operand kann ein Zeiger auf einen beliebigen Typ mit
Ausnahme des generischen Typs Pointer sein, der vor der Dereferenzierung umgewandelt werden muß.
P = Q ist nur dann True, wenn P und Q auf dieselbe Adresse zeigen.
Mit den Operatoren + und – kann der Offset eines Zeichenzeigers erhöht oder erniedrigt werden. Mit dem
Operator – können Sie außerdem den Unterschied zwischen den Offsets zweier Zeichenzeiger berechnen. Für
Zeiger-Operatoren gelten die folgenden Regeln:

Wenn I vom Typ Integer und P ein Zeichenzeiger ist, addiert P + I den Wert I zu der von P angegebenen
Adresse. Es wird also ein Zeiger auf die Adresse zurückgegeben, die I Zeichen hinter P liegt. (Der
Ausdruck I + P entspricht P + I.) P – I subtrahiert I von der Adresse, die von P angegeben wird. Das
Ergebnis ist ein Zeiger auf die Adresse, die I Zeichen vor P liegt.
  Wenn P und Q Zeichenzeiger sind, berechnet P – Q die Differenz zwischen der von P angegebenen
(höheren) und der von Q angegebenen (niedrigeren) Adresse. Es wird also ein Integer-Wert für die Anzahl
der Zeichen zwischen P und Q zurückgegeben. Das Ergebnis von P + Q ist nicht definiert.

Daher die Frage geht es auch ähnlich wie in "C"??

Grüße von der Nordsee

Peter
OlafSt
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 486
Erhaltene Danke: 99

Win7, Win81, Win10
Tokyo, VS2017
BeitragVerfasst: Do 22.01.15 13:36 
Delphi beherrscht Pointer-Artihmetik. Wurde ganz groß gefeiert, aber wenige Wochen später war das ganze geraffel mit Pointern sowas von out, das es gar nicht mehr richtig zum Zuge kam.

Wie der von dir zitierte Abschnitt schon sagt: P+I gibt einen Pointer zurück, der um I Stellen "nach hinten" verschoben ist. Allerdings ist Delphi da etwas cleverer als C. Wenn der Compiler weiß, was für ein Pointer das ist, dann ermittelt er von selbst die Größe der dahinterliegenden Datenstruktur und addiert dann I*Datenstrukturgröße dazu. Von allein, ohne das irgendwer was dazu tun muß.

Ergo: Laß P einen PInteger sein. Dann wird P:=P+1 den Pointer 4 Bytes weiterschieben. Nicht ein Byte, denn ein Integer ist 4 Bytes groß. Da du einen PMessage-Pointertyp hast (und ich nehme einfach mal an, der TMessage-Record dahinter ist 42 Bytes groß), dann ergibt PMessage+1 einen Pointer, der 42 Bytes nach hinten verschoben ist. Denn Delphi weiß, das PMessage einfach nur ein ^TMessage ist, und TMessage ist eine Datenstruktur von 42 Bytes Größe.

Willst du es wie in C haben, muß der Pointer in ein PByte gecastet werden. dann geht Delphi von einem Byte-Pointer aus (dahinterliegenedn Datenstruktur = 1 Byte groß) und dann kann man auch den C-Code 1:1 portieren. PChar geht seit D2009 nicht mehr, denn PChars sind seitdem PWideChars, ergo 2 Bytes groß.

_________________
Lies, was da steht. Denk dann drüber nach. Dann erst fragen.
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Do 22.01.15 16:53 
Hallo OlafSt,

danke für Deine Antwort! Genau so hatte ich es erwartet aber is nich.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
var
  S  : String;
  ps : Pointer;

begin
  PS := @S;
  PS := PS+1;

liefert die Fehlermeldung: "Opperator ist auf diesen Opperandentyp nicht anwendbar" (Zeile 7)

Übrigens "C" ist genauso schlau: "P++" wird abhängig vom Variablentype incrementiert (Kernighan & Ritchie).

Meine Frage ist, worauf ist die Pointerarithmetik anwendbar? Z.B. Integerarrays oder ist da ein Syntaxfehler drin? Egal ob ich String oder Integer verwende, das Ergebnis ist immer das gleiche. Liegt es vielleicht am Typ "Pointer"?
Zitat:
Da du einen PMessage-Pointertyp hast (und ich nehme einfach mal an, der TMessage-Record dahinter ist 42 Bytes groß), dann ergibt PMessage+1 einen Pointer, der 42 Bytes nach hinten verschoben ist. Denn Delphi weiß, das PMessage einfach nur ein ^TMessage ist, und TMessage ist eine Datenstruktur von 42 Bytes Größe.

Stimmt leider nicht, dann hätte ich die Frage nicht gestellt. Es gibt die Fehlermeldung: "Opperator ist auf diesen Opperandentyp nicht anwendbar"
:?:

Grüße von der Nordsee

Peter
baumina
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 305
Erhaltene Danke: 61

Win 7
Delphi 10.2 Tokyo Enterprise
BeitragVerfasst: Do 22.01.15 17:03 
So wie ich das oben lese, solltest du auch erst aus p ein Integer machen, dann 1 dazuzählen und dann den Kram wieder in den Pointer umwandeln.

ausblenden Delphi-Quelltext
1:
PS := Pointer(Integer(PS) + 1);					
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Do 22.01.15 17:53 
Pointer ist nunmal ein Zeiger auf irgendwas, da kann der Compiler die dahinterliegende Größe ja nicht kennen. Anders sieht das bei typisierten Pointern aus.
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
var
  S  : String;
  ps : PChar;
begin
  S := 'Hallo Welt';
  PS := @S[1];
  PS := PS + 1;
  ShowMessage(PS^);
end;
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Fr 23.01.15 11:51 
Hallo baumina,

Dank für Deine Antwort aber siehe oben. :wink:

Hallo WasWeißDennIch,

Dank auch Dir. Dein Beispiel hat funktioniert. Das heißt also die direkte Pointerarithmetik ist nur auf Arrays anwendbar. Sehe ich das richtig??

Grüße von der nebligen Nordsee

Peter
WasWeißDennIch
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 653
Erhaltene Danke: 160



BeitragVerfasst: Fr 23.01.15 12:57 
Das ist eine Frage der Interpretation. Die Daten müssen schon en block im Speicher liegen (wie eben bei Arrays), wenn man sie durchiterieren möchte, was will man auch sonst Sinnvolles auslesen? Außerdem muss dem Compiler die Größe des einzelnen Blocks bekannt sein, was nur bei typisierten Zeigern der Fall ist, der Typ Pointer zählt eben nicht dazu.
Peter18 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 489
Erhaltene Danke: 2


Delphi4
BeitragVerfasst: Fr 23.01.15 18:13 
Hallo WasWeißDennIch,

Die Frage ist aufgetaucht, als ich mit Systemschnittstellen hantiert hsbe. Da kommr ein Block mit ainer variablen Struktur mitten drinn und danach weitere Daten. Das Problem kann demnach nur mit der Krücke "Pointer ==> Integer ==> Addition ==> Pointer" gelöst werden um auf sie folgenden Daten zu zeigen. Schade! Es war aber auch eine prinzipielle Frage.

Grüße von der Nordsee

Peter
SMO
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 120
Erhaltene Danke: 18


D2005 Personal
BeitragVerfasst: Mo 16.02.15 19:22 
user profile iconuall@ogc hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
PInfo := PInfo(Integer(PMessage) + SizeOf(Header))					

Nein, bitte Pointer nicht auf Integer casten! Das funktioniert so zwar problemlos auf 32-Bit-Plattformen, aber das sollte man sich nicht angewöhnen, selbst wenn man nicht vor hat, jemals für 64 Bit zu programmieren.
Korrekter, weil plattformunabhängig, wäre:
ausblenden Delphi-Quelltext
1:
PInfo := PInfo(UIntPtr(PMessage) + SizeOf(Header))					

Statt "UIntPtr" könnte man auch NativeUInt nehmen, aber UIntPtr ist kürzer und ich glaube existierte auch schon bevor NativeUInt eingeführt wurden.


user profile iconOlafSt hat folgendes geschrieben Zum zitierten Posting springen:
Allerdings ist Delphi da etwas cleverer als C. Wenn der Compiler weiß, was für ein Pointer das ist, dann ermittelt er von selbst die Größe der dahinterliegenden Datenstruktur und addiert dann I*Datenstrukturgröße dazu. Von allein, ohne das irgendwer was dazu tun muß.

Äh, das macht C genauso, da hat Peter18 recht. Definierst du "int *ptr" und machst dann "ptr++;", so wird der Zeiger um 4 Bytes (=sizeof(int)) bewegt und nicht um 1 Byte.


user profile iconPeter18 hat folgendes geschrieben Zum zitierten Posting springen:
Niklaus Wirth sei's gedankt, dass solche Sachen nicht so einfach sind wie in "C". Doch viele seiner Gedanken sind bereits aufgeweicht worden (Exit, Goto, Peek, Poke u.s.w.).


Niklaus Wirth hat mit einem modernen Delphi nicht mehr viel zu tun. Das betrifft nicht nur "Exit" usw. sondern eben auch Pointer. Pointerarithmetik geht wunderbar, unter diesen Voraussetzungen:
1. Man begnügt sich mit Inc und Dec.
2. Man hat Delphi 2009 oder neuer:
2. a. Der Pointer-Typ wurde mit der Direktive {$POINTERMATH ON} compiliert
2. b. oder man aktiviert diese Direktive im eigenen Code vor der Nutzung des Pointers.

Die Standardtypen PByte, PAnsiChar, und PChar haben {$POINTERMATH ON}. Vielleicht unterstützen sie auch schon Pointerarithmetik in älteren Delphi-Versionen, das weiß ich nicht mehr (ich glaube PChar konnte es schon länger, aber das sollte man wenn möglich nur für echte Chars benutzen).
PInteger usw. hat standardmäßig keine Pointerarithmetik, aber sie kann aktiviert werden. Das bedeutet:

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:
var
  IntArray: array [0..3of Integer = (0123);
  P: PInteger;

begin
  // lasse P auf Element 0 zeigen
  P := @IntArray[0];
  // lasse P auf Element 2 zeigen
  P := P + 2// Compiler meckert! "Operator not applicable to this operand type"
  Inc(P, 2);  // funktioniert! Bewegt Zeiger in Abhängigkeit der Größe des Typs, hier also 2 Integer = 8 Byte weiter
end;


{$POINTERMATH ON}

begin
  // lasse P auf Element 0 zeigen
  P := @IntArray[0];
  // lasse P auf Element 2 zeigen
  P := P + 2;  // funktioniert! Entspricht exakt "Inc(P, 2)"
  // dank POINTERMATH können Pointer als offene Arrays benutzt werden!
  P[-2] := 10// funktioniert! IntArray[0] ist jetzt = 10
end;