2016-03-10 7 views
9

के साथ डेल्फी प्रक्रियाएं डेल्फी में प्रक्रियाओं और तारों के साथ काम करते समय मुझे एक समस्या का सामना करना पड़ा। तथ्य यह है कि मुझे आउटपुट स्ट्रिंग "1S2S3S4S5S6S" देखने की उम्मीद है लेकिन वास्तविक आउटपुट "1234S5S6" है। डीबग प्रक्रिया के दौरान यह कहता है कि एस 1, एस 2, एस 3 और एस 6 स्ट्रिंग वैरिएबल प्रारंभ नहीं किए गए हैं (एस 1, एस 2, एस 3, एस 6 'स्ट्रिंग्स हैं, एस 4 और एस 5 के पास मूल्य' एस 'है)। क्या कोई मुझे यह समझा सकता है? कोड यह रहा:स्ट्रिंग पैरामीटर

program StringTest; 

{$APPTYPE CONSOLE} 

procedure MyProcedure(S1: String; const S2: String; var S3: String; 
         S4: String; const S5: String; var S6: String; 
         out S7: String); 
begin 
    S7 := '1' + S1 + '2' + S2 + '3' + S3 + '4' + S4 + '5' + S5 + '6' + S6; 
end; 

procedure Work; 
var 
    S: String; 
begin 
    S := 'S'; 
    MyProcedure(S, S, S, S, S, S, S); 
    writeln(S); 
end; 

begin 
    Work; 
    readln; 
end. 
+4

सावधान रहें: जब आप 'const' के साथ पैरामीटर घोषित करते हैं, तो आप संकलक को बता रहे हैं कि उसे उस फ़ंक्शन की अवधि के लिए पैरामीटर को बदलने की अपेक्षा नहीं करनी चाहिए। यह सुनिश्चित करना आपकी ज़िम्मेदारी है कि आप उस वचन को कायम रखें; संकलक इसे आपके लिए जांच नहीं सकता है। इस मामले में, आप 'S7' के माध्यम से' S' संशोधित कर रहे हैं जबकि एक ही समय में 'S2' और' S5' का दावा नहीं होगा। –

उत्तर

17

आपका S7 पैरामीटर एक out पैरामीटर के रूप में घोषित किया जाता है, इसलिए जब समारोह कहा जाता है संकलक एक खाली स्ट्रिंग के लिए पारित चर सेट हो जाएगा। आउटपुट पैरामीटर समेत सभी पैरामीटर के लिए आप S वैरिएबल पास कर रहे हैं, इसलिए S का मान फ़ंक्शन के अंदर पैरामीटर मानों का उपयोग करने से पहले मेमोरी से मिटा दिया जाता है।

विस्तार करने के लिए आगे, प्रक्रिया register बुला सम्मेलन, जहां S1 .. S3 (क्रमशः EAX, EDX, और ECX,) CPU रजिस्टरों में पारित कर रहे हैं और S4 .. S6 बजाय ढेर पर पारित कर रहे हैं उपयोग कर रहा है। इनपुट string चर स्पष्ट वाइप किए जाने से हो रही के बाद अपने वर्तमान मूल्य S4 और S5 के लिए ढेर पर धकेल दिया जाता है (S3 और S6 सिर्फ चर की ओर संकेत करती है), और इससे पहले कि मूल्य S1 और S2 को सौंपा गया है। तो, S1 और S2 अंत तक शून्य, S4 और S5 पोंछ से पहले मूल 'S' आंकड़ों के संकेत दिए गए होते हैं, और S3 और S6string चर कि मिटा दिया गया था पर ओर इशारा करते हैं।

डीबगर आपको यह सब कुछ क्रिया में दिखा सकता है। आप लाइन जहां MyProcedure() कहा जाता है पर एक ब्रेकपाइंट डाल दिया, और फिर सीपीयू दृश्य खोलें, तो आपको निम्न विधानसभा निर्देश देखेंगे:

StringTest.dpr.17: MyProcedure(S, S, S, S, S, S, S); 
00405A6C 8B45FC   mov eax,[ebp-$04] // [ebp-$04] is the current value of S 
00405A6F 50    push eax   // <-- assign S4 
00405A70 8B45FC   mov eax,[ebp-$04] 
00405A73 50    push eax   // <-- assign S5 
00405A74 8D45FC   lea eax,[ebp-$04] 
00405A77 50    push eax   // <-- assign S6 
00405A78 8D45FC   lea eax,[ebp-$04] 
00405A7B E8B0EDFFFF  call @UStrClr  // <-- 'out' wipes out S! 
00405A80 50    push eax   // <-- assign S7 
00405A81 8D4DFC   lea ecx,[ebp-$04] // <-- assign S3 
00405A84 8B55FC   mov edx,[ebp-$04] // <-- assign S2 
00405A87 8B45FC   mov eax,[ebp-$04] // <-- assign S1 
00405A8A E8B9FEFFFF  call MyProcedure 

इसे ठीक करने के लिए, आप एक अलग चर का उपयोग करने के लिए उत्पादन प्राप्त करने की आवश्यकता :

function MyFunction(S1: String; const S2: String; var S3: String; 
         S4: String; const S5: String; var S6: String): String; 
begin 
    Result := '1' + S1 + '2' + S2 + '3' + S3 + '4' + S4 + '5' + S5 + '6' + S6; 
end; 

procedure Work; 
var 
    S: String; 
begin 
    S := 'S'; 
    WriteLn(MyFunction(S, S, S, S, S, S)); 
end; 
:

procedure Work; 
var 
    S, Res: String; 
begin 
    S := 'S'; 
    Proc(S, S, S, S, S, S, Res); 
    WriteLn(Res); 
end; 

वैकल्पिक रूप से, एक समारोह है कि एक out पैरामीटर का उपयोग करने का एक नया String अपने Result के माध्यम से रिटर्न के बजाय में प्रक्रिया को बदलने

+0

उस सलाह के लिए धन्यवाद, लेकिन मुझे अभी भी समझ में नहीं आता कि एस 4 और एस 5 के मूल्य 'एस' क्यों हैं और अन्य नहीं हैं। क्या गलत है? – Alexander

+0

ठीक है, मैं इसे अभी प्राप्त कर रहा हूं :) अंतिम प्रश्न, ऐसा आदेश में ऐसा क्यों होता है? मेरा मतलब है कि एस 4 के मूल्य, एस 5 को पहले स्टैक करने के लिए धक्का दिया जाता है, फिर एस 1, एस 2, एस 3 रजिस्टरों को। – Alexander

+5

यदि रजिस्टर पैरामीटर पहले रजिस्टरों को संग्रहीत किए गए थे, तो @Alexander, तो उन रजिस्टरों को स्टैक पैरामीटर के मानों की गणना करने के लिए कंपाइलर के लिए अनुपलब्ध होगा। संकलक जानता है कि इसे पैरामीटर मानों को किसी भी क्रम में गणना करने की अनुमति है, इसलिए यह संकलक के लिए सुविधाजनक ऑर्डर चुनता है। –

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