Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Pointer/Cardinal-Casterei beenden (https://www.delphipraxis.net/96567-pointer-cardinal-casterei-beenden.html)

BUG 26. Jul 2007 23:24


Pointer/Cardinal-Casterei beenden
 
Hallo Leute,

habe einen Code wie diesen (bisschen mehr/ bisschen sinnvoller :zwinker: ):

Delphi-Quellcode:
type PWord = ^word;

     TdynArray = class
     constructor create(size: cardinal);
     destructor destroy; override;
     private
            size: cardinal;
            data: PWord;
     public
           function getWord(index: cardinal): word;
     end;

constructor TdynArray.create(size: cardinal);
begin
     inherited create;
     getMem(data, size);
end;

destructor TdynArray.destroy;
begin
     freeMem(data, size);
     inherited;
end;

function TdynArray.getWord(index: cardinal): word;
begin
     result := PByte(cardinal(data)+(index shl 1))^; // <= hier ist der böse Code
end;
Der besagte Teil macht mir Bauchschmerzen, da ich einen Zeiger in einen Cardinal caste
:arrow: funktioniert, sieht aber nicht so schick aus und ich weiß nicht, was auf 64-Bit-Maschinen passieren würde :pale:

Kennt ihr eine Alternative?

MfG,
Bug

PS: Dynamische Array kommen nicht in Frage, bei Delphi 3 gibt es solchen Luxus noch nicht :-D

Dax 26. Jul 2007 23:45

Re: Pointer/Cardinal-Casterei beenden
 
Delphi-Quellcode:
function TdynArray.getWord(index: cardinal): word;
begin
     result := PByte(cardinal(data)+(index shl 1))^; // <= hier ist der böse Code
end;
Dieser Code kompiliert? Gut, dann sollte folgendes auch funktionieren:
Delphi-Quellcode:
function TdynArray.getWord(index: cardinal): word;
var temp: PByte;
begin
  temp := PByte(data);
  Inc(temp, index shl 1);
  result := temp^;
end;
Jedenfalls glaube ich, dass das dann geht.. Hab schon lang nix mehr gepointert ;)

edit: Was spricht gegen Array[0..0] und ausgeschaltetes Range-Checking?

SirThornberry 27. Jul 2007 07:20

Re: Pointer/Cardinal-Casterei beenden
 
Warum sollte es denn nicht auf 64bit Maschienen funktionieren? Ein Pointer ist genau so groß wie ein Cardinal. D.h. selbst auf 64bit Maschienen solltest du keine Probleme bekommen wegen dem Cardinal (andernfalls würde das ja sonst bedeuten das du auch mit Pointern ein Problem bekommst)

Muetze1 27. Jul 2007 07:24

Re: Pointer/Cardinal-Casterei beenden
 
Warum überhaupt PByte? Dadurch muss man überhaupt den Index veroppeln...

Warum nicht einfach:
Delphi-Quellcode:
function TdynArray.getWord(index: cardinal): word;
var
  lTemp: PWord;
begin
  lTemp := data;
  Inc(lTemp, index);
  result := lTemp^;
end;

Hawkeye219 27. Jul 2007 08:00

Re: Pointer/Cardinal-Casterei beenden
 
Hallo Bug,

solltest du beim Anfordern/Freigeben des Speichers den Wert size nicht mit der Elementgröße (=SizeOf(Word)) multiplizieren? Oder gibt size gar nicht die Anzahl der Elemente sondern die Arraygröße in Bytes an?

Das interne Feld size wird im Konstruktor nicht initialisiert.

Dein Pointer-Problem kannst du ganz einfach umgehen, indem du das Feld data direkt als Zeiger auf ein Array vereinbarst:

Delphi-Quellcode:
type
  // möglicherweise auch bei Delphi3 schon in SysUtils vereinbart...
  PWordArray = ^TWordArray;
  TWordArray = array [0..(MaxInt div SizeOf(Word)) - 1] of Word;

  TDynArray = class
  private
    FCapacity : Cardinal;
    FData    : PWordArray;
  public
    constructor Create (Capacity: Cardinal);
    destructor Destroy; override;
    function GetWord (Index: Cardinal): Word;
  end;

constructor TDynArray.Create (Capacity: Cardinal);
begin
  inherited Create;
  GetMem (FData, Capacity * SizeOf(Word));
  FCapacity := Capacity;
end;

destructor TDynArray.Destroy;
begin
  FreeMem (FData, FCapacity * SizeOf(Word));
  inherited;
end;

function TDynArray.GetWord (Index: Cardinal): Word;
begin
  Result := FData[Index];
end;
Gruß Hawkeye

BUG 27. Jul 2007 13:04

Re: Pointer/Cardinal-Casterei beenden
 
Danke für die vielen Antworten,

Zitat:

Zitat von SirThornberry
Ein Pointer ist genau so groß wie ein Cardinal.

Wenn das stimmt, ist mein Seelenfrieden gerettet :)

Delphi-Quellcode:
Inc(var X, N: LongInt);
Klappt nicht, der will einen ordinalen Typen, dh. ich müsste wieder casten.

Zitat:

Zitat von Hawkeye219
Oder gibt size gar nicht die Anzahl der Elemente sondern die Arraygröße in Bytes an?

Jup, sollte es zumindest.

Zitat:

Zitat von Hawkeye219
Das interne Feld size wird im Konstruktor nicht initialisiert.

:pale: Im Beispiel vergessen.

Ich werde jetzt die "schönere" Array-basierende Lösung anstreben.

MfG,
Bug

Oxmyx 27. Jul 2007 14:05

Re: Pointer/Cardinal-Casterei beenden
 
Zitat:

Zitat von BUG
Delphi-Quellcode:
Inc(var X, N: LongInt);
Klappt nicht, der will einen ordinalen Typen, dh. ich müsste wieder casten.

Ein Zeiger ist ein ordinaler Typ, und kann problemlos mit Inc verwendet werden. Das tolle an Inc ist sogar, dass es bei einem typisierten Zeiger um die Größe des Typs erhöht, d.h. Inc(pWord) wird pWord um 2 Bytes erhöhen, wenn es ein Zeiger auf ein Word ist.

BUG 27. Jul 2007 15:16

Re: Pointer/Cardinal-Casterei beenden
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Oxmyx
Ein Zeiger ist ein ordinaler Typ, und kann problemlos mit Inc verwendet werden.

Sorry wenn ich dich enttäuschen muss, aber letzteres stimmt bei mir nicht ...

MfG,
Bug

//EDIT: Ich verwende jetzt die Array-basierende Lösung, ohne Probleme :dp:

Chewie 28. Jul 2007 11:18

Re: Pointer/Cardinal-Casterei beenden
 
Versuch mal einen typisierten Zeiger. Bei einem untypisierten Zeiger kann der Compiler nicht wissen, um wie viele Bytes inkrementiert werden soll, was vielleicht zu der Fehlermeldung führt.

Muetze1 28. Jul 2007 15:02

Re: Pointer/Cardinal-Casterei beenden
 
Zitat:

Zitat von BUG
Delphi-Quellcode:
Inc(var X, N: LongInt);
Klappt nicht, der will einen ordinalen Typen, dh. ich müsste wieder casten.

Meine Lösung aus diesem Thread mal ausprobiert anstatt in die Hilfe zu schauen und sagen das klappt nicht? Wie schon richtig erklärt wird, klappt das wunderbar. Wie auch richtig erklärt wird, klappt es bei einem untypisierten Zeiger nicht, weil Delphi nicht die Grösse der Daten ermitteln kann, auf den der Zeiger zeigt (Da kein Typ, daher auch untypisiert). Sobald er typisiert ist, inkrementiert er den Zeiger ohne Probleme.

Inc(ptr);

entspricht

Ptr := ptr + sizeof(ptr^);


bzw:

p += sizeof(*p);


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:06 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz