2016-03-10 29 views
9

Delphi'deki yordam ve dizelerle çalışırken bir sorunla karşılaştım. Gerçek şu ki, "1S2S3S4S5S6S" çıkış dizisini görmeyi bekledim ama gerçek çıktı "1234S5S6". Hata ayıklama işlemi sırasında S1, S2, S3 ve S6 dizesi değişkenlerinin başlatılmadığını söyler (S1, S2, S3, S6 '' dizeleri, S4 ve S5 'S' değerine sahiptir). Birisi bana bunu açıklayabilir mi?Dize parametrelerine sahip Delphi yordamları

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

Dikkat: 'const' ile bir parametre bildirdiğinizde, derleyiciye parametrenin bu işlevin süresi boyunca değişmesini beklememesini söylüyorsunuz. Bu sözü yerine getirdiğinizden emin olmak sizin sorumluluğunuzda; derleyici sizin için kontrol edemez. Bu durumda, S2'yi “S7” ile değiştirirken aynı zamanda S2'yi ve S5'in değişmeyeceğini iddia ediyorsunuz. –

cevap

17

Sizin S7 parametresi bir out parametre olarak ilan edilir, böylece işlev çağrıldığında derleyici boş dize geçirilen değişkeni ayarlar: İşte kod. Çıkış parametresi de dahil olmak üzere tüm parametreler için aynı S değişkenini geçiyorsunuz, böylece S değeri, parametre değerleri işlev içinde kullanılmadan önce bellekten siliniyor.

ayrıca prosedür S6 yerine yığında geçirilir register çağrı S1 .. S3 (sırasıyla EAX, EDX, ve ECX) CPU kayıtları geçirilir kuralı ve S4 .. kullanarak oluşturulması. Geçerli değeri S4 ve S5 (10 ( S3 ve S6 değişkenler için yalnızca işaretçilerdir) yığınının üzerine itildikten sonra ve S1 ve S2 değerlerine atanmadan önce string değişken girdisi silindi. Bu yüzden, S1 ve S2 olarak son sıfır, S4 ve S5 mendil önce özgün 'S' veri işaretçileri içerir ve S3 ve S6 sildi string değişken işaret edilmektedir.

Hata ayıklayıcı, tüm bunları size gösterebilir. Eğer MyProcedure() denir satırda kesme koymak ve sonra CPU görünümünü açmak, aşağıdaki montaj talimatları göreceksiniz:

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 

Bunu düzeltmek için, çıktıyı almak için farklı bir değişken kullanmak gerekir :

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; 

Alternatif olarak, bir out parametresini kullanarak yerine kendi Result aracılığıyla yeni String döndüren bir işlevi prosedür değiştirmek

+0

Bu tavsiye için teşekkürler, ama hala S4 ve S5'in neden 'S' değerine sahip olduğunu ve diğerlerinin yapmadığını anlamıyorum. Sorun nedir? – Alexander

+0

Tamam, şimdi anladım :) Son soru, neden böyle bir düzende oluyor? Demek istediğim, S4, S5'in değerleri ilk önce yığına itilir, sonra da S1, S2, S3 kayıtlara aktarılır. – Alexander

+5

Kayıt parametreleri ilk önce @Alexander registerine kaydedildiyse, derleyici için yığın parametrelerinin değerlerini hesaplamak için bu yazmaçlar kullanılamaz. Derleyici, parametre değerlerini, seçtiği herhangi bir sırada hesaplamasına izin verildiğini bilir, bu nedenle derleyiciye uygun bir sipariş seçer. –