2010-08-09 18 views
7

Eğer Delphi içersinde yeterince yer değiştirirseniz, derleyici tarafından oluşturulan TTypeInfo kayıtları hakkında garip ve görünüşte belgelenmemiş bir şey bulacaksınız. adres X bir TTypeInfo kayda PTypeInfo noktaları X - 4 de bulacaksınız Eğer önümüzdeki 4 bayt Örneğin X'e bir işaretçi açıklar:Orada bir TTypeInfo önce "kimlik işaretçisi" nedir?

procedure test(info: PTypeInfo); 
var 
    addr: cardinal; 
    ptr: PPointer; 
begin 
    addr := cardinal(info); 
    writeln('addr: ', addr); 
    dec(addr, 4); 
    ptr := PPointer(addr); 
    addr := cardinal(ptr^); 
    writeln('addr: ', addr); 
end; 

bu rutin derleyici tarafından üretilen meşru PTypeInfo geçirin, ve aynı adresi iki kez çıkarır. TypInfo.pas'ta biraz dolaştım ama bu "kimlik işaretçisini" ya da ne için var olduğunu belirten bir şey göremiyorum. Bunun neden olduğunu bilen var mı? Bu, Delphi'nin her sürümünde en az D3'ten D2010'a doğru doğru gibi görünüyor.

+1

Yukarıdaki kodda bir "var" eksik olduğunu varsayalım ... –

+0

@Andreas: Nerede? Eksik varsayı göremiyorum ... –

+0

Oops! Tamam, şimdi düzeltildi. –

cevap

10

Çok basit: paketler ve dinamik bağlantı.

BPL'ler DLL'lerdir. DLL'leri yamaları ya da EXE (ya da birden çok işlem arasında salt okunur bellek paylaşımı için büyük bir zarar verecek zarar) karşı DLL bağlanırken tüm kod yerine, yamaları yamaları ile bağlanır. Kodda bir yere TypeInfo(SomeType) ya da bir EXE ya da DLL türünün bir referansına ihtiyaç duyulmasını engellemek için, BPL'ye karşı bağlanırken değiştirilmek yerine, içe aktarma tablosunda bir dolaylılık vardır.

Bu programda bir BPL olarak bağlanıyor karşı statik bağlama farkı görmek kolay: dcc32 test.pas ile derlenmiş benim yerel makinede On

{$apptype console} 
uses TypInfo, SysUtils; 
type 
    TFoo = class(TObject); 
var 
    x: PPTypeInfo; 
begin 
    x := GetTypeData(TypeInfo(TFoo))^.ParentInfo; 
    Writeln(x^^.Name); 
    Writeln(Format('x %p', [x])); 
    Writeln(Format('x^ %p', [x^])); 
end. 

, bu çıkışı:

TObject 
x 00401B64 
x^ 00401B68 

Ama ne zaman dcc32 -LUrtl test.pas ile RTL paketi ile derlenmiş, bu çıktılar:

TObject 
x 004051F0 
x^ 40001DA4 

Umarım bu durumu temizler.

+0

Oldukça benzer bir fikir formüle edecektim.Takım için teşekkürler –

+0

Bu yüzden, işaretçinin işin yapması için linker için bir yer olması gerekiyor ve bu sadece işaret ettiği verilerden hemen önce yerleştiriliyor. Bu veri aynı modülde olduğunda, ne zaman? Tamam, bu mantıklı. Teşekkürler –

+2

@Mason tüm typeinfo fixups - bir blok tipinfo'dan diğerine işaretçiler - PPTypeInfo değil, PTypeInfo değil, dinamik bağlantı durumunun üstesinden gelmek için Statik bağlantı durumunda, sözleşmenin çalışması için bir ara işaretçi olması gerekir, ve tipinfo'nun bir kısmı, herhangi bir şey kadar mantıklıdır. Yani, bu, bağlayıcı için orada değildir, çünkü kongre ve kongre orada, sayfa paylaşımı için potansiyeli en üst düzeye çıkarmak için yapıldığı gibi, dinamik bağlantı nedeniyle oradadır. –

0

belki onun bitişik bellek :) olmak olur bir bağlantılı liste

+0

Hayır, çünkü TTypeInfo/TTypeData yapılarında bir sonraki göstericiye benzeyen hiçbir şey yok. İlginç bir fikir olsa da. –

1

Eğer TypInfo ünitesinde örneğin IsPublishedProp için bir göz olduğu zaman, edeceğiz oluyor ama ne tamamen Dont'anlamak

PTypeInfo(Instance.ClassInfo) 

Eğer ClassInfo yöntemine bakın, değeri vmt tablosuna ilişkin görünüyor basit işaretçi döndürür::

bir TypeInfo yapısına bir işaretçi olarak örneğinin ClassInfo atmalarını görüyoruz
Result := PPointer(Integer(Self) + vmtTypeInfo)^; 

vmtTypeInfo, -72 değerine sahiptir. Bundan önceki 4 bayt, vmtInitTable'dur. vmtTypeInfo DynamicTable vb

vmtInitTable değeri TypeInfo yapısına işaretçi olarak _FinalizeRecord örneğin TObject.CleanupInstance için kullanılan ve geçirilen FieldTable, MethodTable ile takip edilir.

Bu nedenle TypeInfo yapısını işaret eden TypeInfo yapısından önceki dört bayt, tasarım ve vmt yapısının bir kısmı tarafından orada görünmektedir.

Düzenleme Mason haklı olarak yukarıda işaret tam bir kırmızı ringa olduğu gibi

(yorumlar). Cevabı bırakıyorum, böylece başkaları onu kovalamak zorunda kalmayacak.

değişkenler ve adreslerinin üzerinde karışıklığı önlemek için Güncelleştirme, ben şöyle Mason'ın test prosedürü tekrar yazmış:

procedure test(info: PTypeInfo); 
begin 
    writeln('value of info  : ', cardinal(info)); 
    writeln('info - 4   : ', cardinal(info) - 4); 
    writeln('value 4 bytes before: ', cardinal(PPointer(cardinal(info)-4)^)); 
end; 

ve aşağıdaki bilgilerle diyoruz:

procedure TryRTTIStuff; 
begin 
    writeln('TPersistent'); 
    test(TypeInfo(TPersistent)); 

    writeln('TTypeKind enumeration'); 
    test(TypeInfo(TTypeKind)); 

    writeln('Integer'); 
    test(TypeInfo(Integer)); 

    writeln('Nonsense'); 
    test(PTypeInfo($420000)); 
end; 

ilk Üç, Mason'un tarif ettiği sonuçları üretir. Sadece son yazara ait işaretçi değerini göstermek için ekstra bir writeln ekledim. TryRTTIStuff'daki son çağrı, bir gösterici içinde geçerli bir TypeInfo yapısına geçmediğinizde, ilk ve üçüncü writeln'lerin çağrı için aynı değeri alamadığınızı göstermektir.

TypeInfo ile neler olup bittiğine dair bir ipucu yok. Belki de Barry Kelly'ye yeni D2010 RTTI'nin yazarı olduğunu sormalıyız, bu yüzden de eski bir tane hakkında çok şey bilmeli ...

+0

Üzgünüz, ama yanlış bir şeye bakıyorsunuz. TypeInfo, nesne olmayan türler için de mevcut olabileceğinden, VMT'ler ile ilgisizdir. VMT, sınıfın TTypeInfo kaydına bir işaretçi içerir, ama bu benim sorduğum şey değil. –

+0

@Mason: Tam olarak doğru olabilirsiniz, ancak "eski tarz RTTI" nın sadece sınıfları ve numaralandırmalarda TypeInfo özelliğini desteklediğini düşündüm. Ve ikincisi, yalnızca numaralandırma beyanında belirli değerler atamazsanız. Diğer türler için RTTI, D2010'a kadar (Ben D2009 kullanıyorum) ortaya çıkmadı. –

+0

Hayır. Tip bilgisi, DFM'de kullanılabilecek herhangi bir temel tip için mevcut olmalıydı, çünkü sistem icat edildi: seri hale getirme ve serileştirme. –

İlgili konular