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;
- 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.
- 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;