2010-07-07 7 views
5

मैं बहुत तरहयदि कोई प्रक्रिया या फ़ंक्शन पॉइंटर है तो मुझे फ़ील्ड का पता कैसे प्राप्त किया जा सकता है?

function GetSubDataSize(const Rec: TRecord): integer; 
begin 
    Result:=integer(@Rec.Field2) - integer(@Rec.Field1); 
end; 

सब कुछ कुछ बनाया कुछ रिकॉर्ड उप डेटा आकार गणना करना है एक स्थिति को छोड़कर ठीक है, अगर फील्ड में से एक एक प्रक्रिया या समारोह सूचक है, इसलिए

के मामले में
TRecord = record 
    Field2: procedure(Sender: TObject) of object; 
end; 

फ़ंक्शन को प्रक्रिया का पता ही मिलता है। फ़ील्ड का पता पाने के लिए फ़ील्ड का पता लगाने के लिए फ़ील्ड टाइप करने का कोई तरीका है? मुझे पता है कि मैं इसे संस्करण भाग रिकॉर्ड के साथ हल कर सकता हूं, लेकिन इसका उपयोग न करना पसंद करता हूं।

धन्यवाद,

मैक्स

उत्तर

11

क्या आपने @@ की कोशिश की है?

type 
    TRecord = record 
    Field1:integer; 
    Field2:TNotifyEvent; 
    end; 

function GetSubDataSize(const Rec: TRecord): integer; 
begin 
    result := integer(@@Rec.Field2) - integer(@Rec.Field1); 
end; 

मुझे 8 देता है, जो है जो मैं डेल्फी 2010

एन पर उम्मीद @

+6

+1 - दस्तावेज़ों (प्रक्रियात्मक प्रकार) से: "प्रक्रियात्मक चर के स्मृति पते (इसमें संग्रहीत पते के बजाए), @ @। " –

+0

धन्यवाद, नेट, ऐसा लगता है कि डेल्फी कौशल का परीक्षण करने के लिए यह एक अच्छा सवाल है, आप इसे आसानी से पारित कर रहे हैं;) – Maksee

+0

@Maksee: धन्यवाद! मैं नहीं कहूंगा कि मेरे कौशल दूसरों की तुलना में बेहतर हैं (विशेष रूप से मेसन!), मुझे बस एक बार एक ही समस्या को हल करना पड़ा। :) – Nat

1

दुर्भाग्य से, वहाँ इस तरह से आप इसे कर रहे हैं करने के लिए कोई आसान तरीका होने के लिए प्रतीत नहीं होता। संस्करण भाग रिकॉर्ड शायद काम करेंगे, लेकिन मैं सहमत हूं, यह थोड़ी बदसूरत है।

लेकिन यदि आप डेल्फी 2010 पर हैं, तो बेहतर तरीका है। ऐसा लगता है कि आप रिकॉर्ड के सभी क्षेत्रों में जाने और अपने ऑफसेट निर्धारित करने की कोशिश कर रहे हैं। यही कारण है कि विस्तारित RTTI के साथ किया जा सकता है, तो जैसे:

procedure test; 
var 
    ctx: TRttiContext; 
    recType: TRttiType; 
    recField: TRttiField; 
begin 
    ctx := TRttiContext.Create; 
    recType := ctx.GetType(TypeInfo(TMyRec)); 
    for recField in recType.GetFields do 
    writeln(format('Field %s is at offset %d.', [recField.Name, recField.Offset])); 
end; 

(writeln मान लिया गया है कि आप एक सांत्वना अनुप्रयोग प्रदर्शन-परक प्रयोजनों के लिए विशुद्ध रूप से लिखा है, जैसे मैं लिखा यह परीक्षण करने के लिए कर रहे हैं सूट करने के लिए इसे संशोधित करने के लिए स्वतंत्र महसूस करें। अपनी आवश्यकताओं ...)

3

अपने फ़ील्ड 2 के रूप में एक विधि सूचक, तो आप उस का उपयोग करना चाहिए है:

इस कोड को एक ज्ञापन ओ के साथ एक फार्म की OnCreate में

type 
    RRecord = record 
    Field1: Integer; 
    Field2: procedure (Sender: TObject) of object; 
    Field3: Integer; 
    end; 

var 
    rec: RRecord; 
begin 
    Memo1.Lines.Add(Format('@rec.Field1 %d', [Integer(@rec.Field1)])); 
    Memo1.Lines.Add(Format('@rec.Field2 %d', [Integer(@rec.Field2)])); 
    Memo1.Lines.Add(Format('@TMethod(rec.Field2).Code %d', [Integer(@TMethod(rec.Field2).Code)])); 
    Memo1.Lines.Add(Format('@TMethod(rec.Field2).Data %d', [Integer(@TMethod(rec.Field2).Data)])); 
    Memo1.Lines.Add(Format('@rec.Field3 %d', [Integer(@rec.Field3)])); 
end; 

पुट n यह, निर्माण करता है:

@rec.Field1 1244820 
@rec.Field2 4052 
@TMethod(rec.Field2).Code 1244828 
@TMethod(rec.Field2).Data 1244832 
@rec.Field3 1244836 

दूसरी पंक्ति एक यादृच्छिक मूल्य पता चलता है, कुछ भी नहीं के रूप में स्थानीय रिकॉर्ड चर को सौंपा गया था। तीसरी और चौथी रेखाएं टीएमआईडी सदस्यों के पते दिखाती हैं।

कृपया ध्यान दें कि रिकॉर्ड में भरना (हो सकता है) इस तथ्य के कारण है कि विधियां हमेशा 8 बाइट गठबंधन होती हैं। (कम से कम डी 200 9/डी -2010 में)।

+0

> हैं "रिकॉर्ड में ..filling .." - @Marjan, मैं इसे ले ' मैंने कहा, 'वर्ड' फील्ड 1 और 'पैक' रिकॉर्ड के साथ परीक्षण किया है? D2007 के साथ कोई संरेखण नहीं है .. –

+0

@Sertac: नहीं, क्षमा करें। मैंने दिए गए उदाहरण में अतिरिक्त बाइट्स को देखा और पिछले अनुभव से पता चला कि डी 2010 और डी 200 9 8 बाइट सीमाओं पर विधि पॉइंटर्स को संरेखित करना प्रतीत होता है। इसे किसी वर्ग में खोजा गया है जो एक अन्य वर्ग की एक सटीक प्रति (फ़ील्ड वार) होनी चाहिए जो घोंसला वाली रिकॉर्ड परिभाषा होती है। हमारे पास अनजान परिवर्तनों का पता लगाने के लिए उदाहरण के आकार पर एक रन टाइम चेक है, लेकिन दूसरे नहीं। यह जांच कभी-कभी सफल होती है और कभी-कभी विफल होती है, हमेशा कक्षा में बदलाव किए बिना, लेकिन अन्य कोड में परिवर्तन के साथ। हमारी प्रतिलिपि के आस-पास {$ A8} डालकर इसे हल किया गया। –

+0

मैं थोड़ी उलझन में हूं; AFAIK '{$ A8}' पहले से ही डिफ़ॉल्ट संरेखण है।तो एक 'बाइट' या 'टीएमआईडी' डिफ़ॉल्ट रूप से एक गैर-पैक रिकॉर्ड के लिए 8 बाइट सीमा पर निर्भर करेगा .. फिर भी स्पष्टीकरण के लिए धन्यवाद, मुझे लगता है कि मैंने किसी तरह से गलत समझा है .. –

संबंधित मुद्दे

 संबंधित मुद्दे