2008-11-18 12 views
16

आम तौर पर, डेल्फी में एक 'कॉन्स की सरणी' विधि का उपयोग करके तर्कों की एक चर संख्या के साथ एक समारोह घोषित करेगा। हालांकि, सी में लिखे गए कोड के साथ संगतता के लिए, एक अज्ञात 'varargs' निर्देश है जिसे फ़ंक्शन घोषणा में जोड़ा जा सकता है (मैंने रूडी के उत्कृष्ट 'Pitfalls of convering' दस्तावेज़ को पढ़ने के दौरान यह सीखा)।'varargs' के साथ एक फ़ंक्शन स्टैक की सामग्री को कैसे पुनर्प्राप्त कर सकता है?

उदाहरण के लिए, एक सी में एक समारोह हो सकता था, इस तरह की घोषणा की:

void printf(const char *fmt, ...) 

डेल्फी में, यह बन गयी:

procedure printf(const fmt: PChar); varargs; 

मेरा प्रश्न है: मैं कैसे प्राप्त कर सकते हैं 'varargs' निर्देश के साथ परिभाषित एक विधि को लागू करते समय ढेर की सामग्री?

मुझे उम्मीद है कि इसके लिए कुछ टूलिंग मौजूद है, जैसे va_start(), va_arg() और va_end() फ़ंक्शंस के डेपी अनुवाद, लेकिन मुझे यह कहीं भी नहीं मिल रहा है।

कृपया मदद करें!

पीएस: कृपया 'क्यों' या 'कॉन्स ऑफ़ एन्स' विकल्प के बारे में चर्चाओं में मत डालें - मुझे Xbox गेम के अंदर कार्यों के लिए सी-जैसे पैच लिखने की आवश्यकता है (डेल्फी एक्सबॉक्स एमुलेटर प्रोजेक्ट देखें ' विवरण के लिए स्रोत फोर्ज पर डीएक्सबीएक्स ')।

उत्तर

18

ठीक है, मुझे आपके प्रश्न में स्पष्टीकरण का अर्थ यह है कि आपको डेल्फी में सी आयात को लागू करने की आवश्यकता है। उस स्थिति में, आपको स्वयं को varargs को लागू करने की आवश्यकता है।

मूल ज्ञान की आवश्यकता x86 पर सी कॉलिंग सम्मेलन है: ढेर नीचे बढ़ता है, और सी दाएं से बाएं तर्कों को धक्का देता है। इस प्रकार, अंतिम घोषित तर्क के लिए एक सूचक, आखिरी घोषित तर्क के आकार से बढ़ने के बाद, पूंछ तर्क सूची को इंगित करेगा। तब से, यह तर्क को गहराई से स्थानांतरित करने के लिए तर्क को पढ़ने और उचित आकार से पॉइंटर को बढ़ाने का विषय है। 32-बिट मोड में x86 स्टैक आमतौर पर 4-बाइट गठबंधन होता है, और इसका यह भी अर्थ है कि बाइट्स और शब्द 32-बिट पूर्णांक के रूप में पास किए जाते हैं।

किसी भी तरह, यहां एक डेमो प्रोग्राम में एक सहायक रिकॉर्ड है जो दिखाता है कि डेटा को कैसे पढ़ा जाए। ध्यान दें कि डेल्फी विस्तारित प्रकारों को एक बहुत ही विचित्र तरीके से गुजर रहा है; हालांकि, आपको इसके बारे में चिंता करने की ज़रूरत नहीं होगी, क्योंकि 10-बाइट फ्लोट आमतौर पर सी में व्यापक रूप से उपयोग नहीं किए जाते हैं, और नवीनतम एमएस सी, आईआईआरसी में भी लागू नहीं किए जाते हैं।

{$apptype console} 

type 
    TArgPtr = record 
    private 
    FArgPtr: PByte; 
    class function Align(Ptr: Pointer; Align: Integer): Pointer; static; 
    public 
    constructor Create(LastArg: Pointer; Size: Integer); 
    // Read bytes, signed words etc. using Int32 
    // Make an unsigned version if necessary. 
    function ReadInt32: Integer; 
    // Exact floating-point semantics depend on C compiler. 
    // Delphi compiler passes Extended as 10-byte float; most C 
    // compilers pass all floating-point values as 8-byte floats. 
    function ReadDouble: Double; 
    function ReadExtended: Extended; 
    function ReadPChar: PChar; 
    procedure ReadArg(var Arg; Size: Integer); 
    end; 

constructor TArgPtr.Create(LastArg: Pointer; Size: Integer); 
begin 
    FArgPtr := LastArg; 
    // 32-bit x86 stack is generally 4-byte aligned 
    FArgPtr := Align(FArgPtr + Size, 4); 
end; 

class function TArgPtr.Align(Ptr: Pointer; Align: Integer): Pointer; 
begin 
    Integer(Result) := (Integer(Ptr) + Align - 1) and not (Align - 1); 
end; 

function TArgPtr.ReadInt32: Integer; 
begin 
    ReadArg(Result, SizeOf(Integer)); 
end; 

function TArgPtr.ReadDouble: Double; 
begin 
    ReadArg(Result, SizeOf(Double)); 
end; 

function TArgPtr.ReadExtended: Extended; 
begin 
    ReadArg(Result, SizeOf(Extended)); 
end; 

function TArgPtr.ReadPChar: PChar; 
begin 
    ReadArg(Result, SizeOf(PChar)); 
end; 

procedure TArgPtr.ReadArg(var Arg; Size: Integer); 
begin 
    Move(FArgPtr^, Arg, Size); 
    FArgPtr := Align(FArgPtr + Size, 4); 
end; 

procedure Dump(const types: string); cdecl; 
var 
    ap: TArgPtr; 
    cp: PChar; 
begin 
    cp := PChar(types); 
    ap := TArgPtr.Create(@types, SizeOf(string)); 
    while True do 
    begin 
    case cp^ of 
     #0: 
     begin 
     Writeln; 
     Exit; 
     end; 

     'i': Write(ap.ReadInt32, ' '); 
     'd': Write(ap.ReadDouble, ' '); 
     'e': Write(ap.ReadExtended, ' '); 
     's': Write(ap.ReadPChar, ' '); 
    else 
     Writeln('Unknown format'); 
     Exit; 
    end; 
    Inc(cp); 
    end; 
end; 

type 
    PDump = procedure(const types: string) cdecl varargs; 
var 
    MyDump: PDump; 

function AsDouble(e: Extended): Double; 
begin 
    Result := e; 
end; 

function AsSingle(e: Extended): Single; 
begin 
    Result := e; 
end; 

procedure Go; 
begin 
    MyDump := @Dump; 

    MyDump('iii', 10, 20, 30); 
    MyDump('sss', 'foo', 'bar', 'baz'); 

    // Looks like Delphi passes Extended in byte-aligned 
    // stack offset, very strange; thus this doesn't work. 
    MyDump('e', 2.0); 
    // These two are more reliable. 
    MyDump('d', AsDouble(2)); 
    // Singles passed as 8-byte floats. 
    MyDump('d', AsSingle(2)); 
end; 

begin 
    Go; 
end. 
+1

यह बहुत अच्छा लग रहा है! मुझे आश्चर्य हुआ कि ईएसपी रजिस्टर सामग्री प्राप्त करने के लिए वास्तव में असेंबली का उपयोग करने की आवश्यकता नहीं है। इसके लिए धन्यवाद - महान उदाहरण भी! – PatrickvL

+1

ध्यान दें कि कोड को अनुकूलन की आवश्यकता है यदि यह x64 पर काम करना है - विशेष ट्रंकेट पॉइंटर्स में संरेखण फ़ंक्शन 32-बिट मानों पर संरेखित करें। –

2

मैं this पाया (एक guy से हम जानते हैं :))

इस सामग्री लिखने के लिए ठीक से आप BASM, डेल्फी के, और कोड कॉल एएसएम में अनुक्रम कोडांतरक में बनाया का उपयोग करना होगा। उम्मीद है कि आपको एक अच्छा पता है कि आपको क्या करना है। शायद पर अटक जाए तो .basm समूह में एक पोस्ट मदद करेगा।

1

डेल्फी आपको एक varargs दिनचर्या लागू करने नहीं देता है। यह केवल बाहरी सीडीसीएल कार्यों को आयात करने के लिए काम करता है जो इसका उपयोग करते हैं।

चूंकि varargs सीडीईसी कॉलिंग सम्मेलन पर आधारित है, इसलिए आपको मूल रूप से डेल्फी में असेंबली और/या विभिन्न प्रकार के पॉइंटर मैनिपुलेशन का उपयोग करके इसे पुनः लागू करने की आवश्यकता है।

+0

नहीं, तर्कों की सूची केवल शून्य-समाप्त हो जाती है यदि कॉलर अंतिम तर्क के रूप में शून्य पास करता है। आपके द्वारा उद्धृत पृष्ठ ऐसा कहता है। Printf फ़ंक्शन को सूची को समाप्त करने के लिए शून्य होने की आवश्यकता नहीं है क्योंकि यह पता लगा सकता है कि प्रारूप स्ट्रिंग के आधार पर कितने तर्क हैं। –

+0

ठीक है, मेरी गलती। मैं तदनुसार संपादित करूंगा। –

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

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