ठीक है, मुझे आपके प्रश्न में स्पष्टीकरण का अर्थ यह है कि आपको डेल्फी में सी आयात को लागू करने की आवश्यकता है। उस स्थिति में, आपको स्वयं को 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.
यह बहुत अच्छा लग रहा है! मुझे आश्चर्य हुआ कि ईएसपी रजिस्टर सामग्री प्राप्त करने के लिए वास्तव में असेंबली का उपयोग करने की आवश्यकता नहीं है। इसके लिए धन्यवाद - महान उदाहरण भी! – PatrickvL
ध्यान दें कि कोड को अनुकूलन की आवश्यकता है यदि यह x64 पर काम करना है - विशेष ट्रंकेट पॉइंटर्स में संरेखण फ़ंक्शन 32-बिट मानों पर संरेखित करें। –