Delphi Can

Orjinalini görmek için tıklayınız: Pointer Dereferencing Hakkında.
Şu anda (Arşiv) modunu görüntülemektesiniz. Orjinal Sürümü Görüntüle internal link
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
 System.SysUtils;

type

 PNode = ^TNode;

 TNode = record
   Value: Integer;
   Node: Pointer;
 end;

var
 ANode1: TNode;
 ANode2: TNode;
 ANode3: TNode;
 V : Integer;
begin

 ANode3.Value := 31;
 ANode2.Node := @ANode3;
 ANode1.Node := @ANode2;

 V := //?
end.
Yukarıdaki örnek programda V değişkeni üzerine, ANode3.Value üzerindeki değerin okunması istenmektedir.
Fakat doğrudan V := ANode3.Value gibi bir kullanım istenmeyip, ANode1 değişkeni üzerinden erişim sağlanması istenmektedir.

Not : Dileyen yukarıdaki benzer yapıyı ve çözümü C/C++ ile kodlayıp çözüm sunabilir.
Kolay gelsin.
V := PNode(PNode(ANode1.Node)^.Node)^.Value;

Tabi telefondan değil de bilgisayardan yazıyor olsaydım herbir Node un bir PNode olup olmadığını, Nil olup olmadığını ve derefere edip edemediğimi falan da kontrol ettirirdim...
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
System.SysUtils;

type

PNode = ^TNode;

TNode = record
  Value: Integer;
  Node: Pointer;
end;

var
ANode1: TNode;
ANode2: TNode;
ANode3: TNode;
V : Integer;
begin

ANode3.Value := 31;
ANode2.Node := @ANode3;
ANode1.Node := @ANode2;

asm
  mov eax, DWORD ptr ds:ANode1 + 16
  mov V, eax
end;

Writeln(IntToStr(V));
Readln;

end.
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
System.SysUtils;

type

PNode = ^TNode;

TNode = record
 Value: Integer;
 Node: Pointer;
end;

var
ANode1: TNode;
ANode2: TNode;
ANode3: TNode;
V : Integer;
p1: PNode;
begin

ANode3.Value := 31;
ANode2.Node := @ANode3;
ANode1.Node := @ANode2;
// V := PNode(PNode(ANode1.Node)^.Node)^.Value;  /// The_aLiEn   Çalışıyor
{asm
 mov eax, DWORD ptr ds:ANode1 + 16       ///QuAdR  Çalışıyor
 mov V, eax
end;}

{p1:=PNode(ANode1.Node).Node;
V:=p1.Value;  }                          // Çalışıyor

{
  V:=integer(Pointer(NativeInt(@ANode1) + 16)^);         //çalışıyor
}

{
   V:=integer(Pointer(NativeInt(@ANode1.Node) + 12)^);         //çalışıyor
}
   V:=integer(Pointer(NativeInt(@PNode(ANode1.Node).Node) + 4)^);          //çalışıyor
 Writeln(IntToStr(V));
Readln;

end.
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
 System.SysUtils;

type

 TNode = record
   Value: Integer;
   Node: Pointer;
 end;
 PNode = ^TNode;

var
 ANode1  : TNode;
 ANode2  : TNode;
 ANode3  : TNode;
 V       : Integer;
 p1      : PNode;
 //NOD   : TNode;

begin
 ANode3.Value := 31;
 ANode2.Node := @ANode3;
 ANode1.Node := @ANode2;

 { V := PNode(PNode(ANode1.Node)^.Node)^.Value; }                  // The_aLiEn   Çalışıyor
 { asm mov eax, DWORD ptr ds:ANode1 + 16 mov V, eax end; }         // QuAdR       Çalışıyor
 { p1:=PNode(ANode1.Node).Node; V:=p1.Value; }                     // Savasbd     Çalışıyor
 { V:=integer(Pointer(NativeInt(@ANode1) + 16)^); }                // Savasbd     Çalışıyor
 { V:=integer(Pointer(NativeInt(@ANode1.Node) + 12)^); }           // Savasbd     Çalışıyor
 { V:=integer(Pointer(NativeInt(@PNode(ANode1.Node).Node) + 4)^);} // Savasbd     Çalışıyor

 p1 := PNode(@ANode1);
 while (p1.Node <> nil) do begin
        p1 := PNode(p1.Node);
        if (p1.Node = nil) then V := p1.Value;
        //V := p1.Value;
 end;
 {
 NOD := ANode1;
 while (NOD.Node <> nil) do begin
        NOD := PNode(NOD.Node)^;
        V := NOD.Value;
 end;
 }

 Writeln(IntToStr(V));
 Readln;

end.
Öncelikle değer verip ilgilenen herkese teşekkür ederim.
Benim de ilk çözme yöntemim The_aLiEn hocam'ın gibi oldu.

Alternatif çözüm olsun diye yazıyorum.Fakat kodun anlaşılmasını ve hata ayıklamasını zorlaştırıyor.
program Project1;

{$APPTYPE CONSOLE}
{$R *.res}

uses
 System.SysUtils;

type

 PNode = ^TNode;

 TNode = record
   Value: Integer;
   Node: Pointer;
 end;

var
 ANode1: TNode;
 ANode2: TNode;
 ANode3: TNode;
 V: Integer;
begin
 ANode3.Value := 31;
 ANode2.Node := @ANode3;
 ANode1.Node := @ANode2;

 V := PNode(PPointer(PNode(PPointer(ANode1.Node))^.Node))^.Value;

end.

Benzer şekilde C/C++ çözümü.
#include <iostream>
using namespace std;

typedef void *PVOID;

typedef struct TNode
{
    int Value;
    PVOID Node;

} *PNode;

int main()
{
   int V = 0;
   TNode node1, node2, node3;
   node3.Value = 31;
   node2.Node = &node3;
   node1.Node = &node2;

   V = PNode(PNode(node1.Node)->Node)->Value;

   cout << V << endl;
   return 0;
}
Naçizane bir şeyler söylemek isterim:

 TNode = record
  Value: Integer;
  Node: Pointer;
end;

asm
 mov eax, DWORD ptr ds:ANode1 + 16
 mov V, eax
end;


  1. Sistemin 32-bit'lik olduğu varsayılmıyor mu? 64-bit'lik olduğunda (ve tabiki ilgili register düzenlemesiyle) +16 bytelık offset doğru adresi point etmeyecek, DWORD ptr ifadesi doğru adresi derefere etmeyecektir.
  2. Record field sırasının değişmeyeceğinin garantisi var mı? Field'ların yerlerini değiştirdiğinizde ya da araya bir başka field eklediğinizde hatalı sonuç üretecektir ya da AV hatası alacaktır.

while (p1.Node <> nil) do
...
if (p1.Node = nil) then V := p1.Value;

Derlenme aşamasında değişkenlerin nil/zero initialization kodlarının yerleştirilmediği durumda, ki derleyici bu initialization kodlarını yerleştirir, sonsuz döngüye girmeye kalkışacak, ilk fırsatta da AV hatası alacaktır. Mesela

ANode3.Node := @ANode1;

ya da

ANode3.Node := Pointer($FFFFFFFF);

Kodun hızlı çalışması hedeflenmeli elbette, ama ya bug-free kalabilmesi? Mevcudu düzeltmek için harcanacak vakitle yeni şeyler üretilebilir böylece.

Şu an adreslemek istediğim iki konu Hard Coding ve Value Checking aslında.

Sürç-ü lisan? Rica ile, affola..
Saf pointerler üzerinden gidecek olursak;

ANode3.Node := Pointer($FFFFFFFF);

Bu tarz bir kullanımın kaderi, varacağı yer, her durumda access violation ile sonuçlanmak olacaktır. Böyle kullanılırsa zaten bundan bir kaçış yok, dolayısıyla bu tarz bir sorunla karşılaşmamanın en kolay yolu, daha en baştan o yola sapmamaktan geçer. Öbür türlüsü try except...

{ V := PNode(PNode(ANode1.Node)^.Node)^.Value; }
{ asm
      mov eax, DWORD ptr ds:ANode1 + 16
      mov V, eax
  end; }
{ p1:=PNode(ANode1.Node).Node; V:=p1.Value; }
{ V:=integer(Pointer(NativeInt(@ANode1) + 16)^); }
{ V:=integer(Pointer(NativeInt(@ANode1.Node) + 12)^); }
{ V:=integer(Pointer(NativeInt(@PNode(ANode1.Node).Node) + 4)^);}

Tarzında bir kullanıma gelecek olursak (ki özünde tümü aynı yöntem), o zaman ben de mevcut soruyu şu şekilde bükeyim; "Eleman sayısının belli olmadığı bir durumda" yukarıdaki kodlar bizi sonuca ulaştırır mı?

"Sonsuz döngüden çıkma konusunda" ise aklıma iki alternatif geliyor, ya makul bir sayaç değeri ile döngüden kaçılır (ki eksik bir yol olmuş olur), ya da işlenen her adres daha önceden işlenmiş mi ona bakılır.
 V := PNode(PNode(ANode1.Node).Node)^.Value;