FOR - DO nun çalışma anormalliği

Delphi'de kod yazma ile ilgili sorularınızı bu foruma yazabilirsiniz.
Cevapla
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

FOR - DO nun çalışma anormalliği

Mesaj gönderen vkamadan »

Merhaba dostlar,
Bu gün oldukça ilginç bir olayla karşılaştım uzun araştırmalar sonucu problemin basit bir modelini çıkarttım , Delphi 5 , 7 ve 2007 de denedim hepsindede aynı hatalı sonuçla karşılşatım.

Kod: Tümünü seç

procedure Yordam;
var
i , ilevel:Integer;
begin
  i := 0;
  ilevel :=0;

   for i := 0 to ilevel - 1 do
     begin

     end;

     ShowMessage(IntToStr(i));

 // i değişkeni ekrana  1220544 gibi rast gele bir değer yazıyor,

end;



var
i , ilevel:Integer;
begin
  i := 0;
  ilevel :=0;

   for i := 0 to 0 - 1 do
     begin

     end;

     ShowMessage(IntToStr(i));

 // i değişkeni bu kez doğru bir şekilde ekrana  0 değerini yazıyor,

end;

Ben hiç bir şey anlamadım bu bir BUG olabilirmi ? ama elimdeki bütün delphi versiyonlarında test ettim hepsinde bu sorun var, eğer bu bir sorunsa biz nasıl güvenipte for döngüsü kuracağız.
Volkan KAMADAN
www.polisoft.com.tr
Kullanıcı avatarı
aslangeri
Moderator
Mesajlar: 4322
Kayıt: 26 Ara 2003 04:19
Konum: Ankara
İletişim:

Re: FOR - DO nun çalışma anormalliği

Mesaj gönderen aslangeri »

s.a.
kodları derlediğiniz zaman compiler mesajlarına bakarsanız
FOR - loop variable'i' maybe undefined after loop
dediğini görebilirsiniz.
vkamadan yazdı:....biz nasıl güvenipte for döngüsü kuracağız.
for döngüsü için kullandığımız değişkeni for döngüsü içinde kullanıyoruz. iki örnekte döngü içine girmiyor. bu durumda güven ile ilgili tek sorun "loop variable" ı olan "i" yi "after loop" da kullanmak istediğimiz zaman oluyor ondada "maybe undefined".

Problemin sebebi ise ilk örnekte

Kod: Tümünü seç

 i:=0; 
atamasının derlemeye dahil edilmesi. çünkü bu değişkene değer atıldıktan sonra kullanılmıyor. ikinci örnekteki "i" derlemeye dahil edildiği için problem olmuyor.
eğer "i" değişkenine değer attıktan sonra onu bir işlemde kullanırsanız bir problem oluşmuyor.
şöyleki

Kod: Tümünü seç

var
i , ilevel:integer;
begin
  i := 0;//normalde bu satır derlemeye dahil edilmiyor.
  ShowMessage(IntToStr(i));//bu satır ile i değişkenini kullanıdğımız için yukardaki satır derlemeye dahil oluyor.
  ilevel :=0;

   for i := 0 to (ilevel - 1) do
     begin

     end;

     ShowMessage(IntToStr(i));

// i değişkeni ekrana  artık 0 yazıyor.
kolay gelsin.
Duyduğun Şeylerin Söylediklerim Olduğuna Eminim Ama
Anladığın Şeylerin Anlatmak İstediklerim Olduğuna Emin Değilim
emin_as
Üye
Mesajlar: 559
Kayıt: 01 Eki 2008 10:05
Konum: izmir
İletişim:

Re: FOR - DO nun çalışma anormalliği

Mesaj gönderen emin_as »

Delphi kodu derlerken ikinci for döngüsünün işlemeyecegini anlayıp, o kısmı iptal ediyor.

ilk döngüye ise çalıştırmak için giriyor ve i degişkenine bakıp, döngünün çalışıp çalışmayacagını anlamaya çalışıyor. Bu sırada i ye yaptıgı müdahale kalıyor ve döngüyü işletmeden çıkıyor.

Bu hata sayılabilir, çünkü i degişkenine müdahale ediliyor.

Bu hata sayılmayabilir, hiçbir programcı for döngüsü için kullandıgı degişkeni for döngüsü dışında kullanmamalıdır.

Her iki durumda da for döngüsü içine yazılan kod çalışmıyor.
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

Re: FOR - DO nun çalışma anormalliği

Mesaj gönderen vkamadan »

@aslangeri ve @emin_as bilgiler için çok teşekkür ederim, ever warning kısmında yazanları gözardı ediyorum genelde, buda bana ders olsun oraya dikkat edeyim, evet aslında mantık olarak döngü değişkenlerini döngü dışında kullanmamak en sağlıklısı.
İyi çalışmalar diliyorum.
Volkan KAMADAN
www.polisoft.com.tr
emin_as
Üye
Mesajlar: 559
Kayıt: 01 Eki 2008 10:05
Konum: izmir
İletişim:

Re: FOR - DO nun çalışma anormalliği

Mesaj gönderen emin_as »

Delphi e ait bir bug bu, bug in kaynagını buldum.

Aşagıdaki assembler kodları inceleyince şöyle bir problem var.

i:=0;
ilevel:=0;
for i:=0 to ilevel-1 do

Şeklinde başlayan ilk kodda optimizasyon geregi, i için kullanılan ebx sıfırlanmıyor.


i:=0;
ilevel:=0;
showmessage(intToStr(i));
for i:=0 to ilevel-1 do
Bu kodda ise i i için kullanılan ebx degişkeni sıfırlanıyor.

Hata olmasının nedeni şu, showmessage ile i yazıldıgı için ebx degişkeni sıfırlanmayınca, rasgele bir degişken yazılmış oluyor.

Assembler kodları aşagıya ekledim. Elle sıfırlanınca dogru sonuç yazıyor.
asm
xor ebx,ebx
end;


İ nin ebx in sıfırlanmadıgı kod.

Kod: Tümünü seç

Unit5.pas.28: begin
0045BF4C 55               push ebp
0045BF4D 8BEC             mov ebp,esp
0045BF4F 33C9             xor ecx,ecx
0045BF51 51               push ecx
0045BF52 51               push ecx
0045BF53 51               push ecx
0045BF54 51               push ecx
0045BF55 53               push ebx
0045BF56 33C0             xor eax,eax
0045BF58 55               push ebp
0045BF59 68D3BF4500       push $0045bfd3
0045BF5E 64FF30           push dword ptr fs:[eax]
0045BF61 648920           mov fs:[eax],esp
Unit5.pas.30: ilevel:=0;
0045BF64 33C0             xor eax,eax
Unit5.pas.31: for i := 0 to ilevel-1  do
0045BF66 48               dec eax
0045BF67 85C0             test eax,eax
0045BF69 7C07             jl $0045bf72
0045BF6B 40               inc eax
0045BF6C 33DB             xor ebx,ebx
Unit5.pas.33: end;
0045BF6E 43               inc ebx
Unit5.pas.31: for i := 0 to ilevel-1  do
0045BF6F 48               dec eax
0045BF70 75FC             jnz $0045bf6e
Unit5.pas.34: showmessage('cikti 1:'+IntToStr(i));
0045BF72 8D55F8           lea edx,[ebp-$08]
0045BF75 8BC3             mov eax,ebx
0045BF77 E8E8C7FAFF       call IntToStr
0045BF7C 8B4DF8           mov ecx,[ebp-$08]
0045BF7F 8D45FC           lea eax,[ebp-$04]
0045BF82 BAE8BF4500       mov edx,$0045bfe8
0045BF87 E8DC8BFAFF       call @LStrCat3
0045BF8C 8B45FC           mov eax,[ebp-$04]
0045BF8F E8EC10FDFF       call ShowMessage
Unit5.pas.35: i:=0;
0045BF94 33DB             xor ebx,ebx
Unit5.pas.39: showmessage('cikti 2:'+IntToStr(i));
0045BF96 8D55F0           lea edx,[ebp-$10]
0045BF99 8BC3             mov eax,ebx
0045BF9B E8C4C7FAFF       call IntToStr
0045BFA0 8B4DF0           mov ecx,[ebp-$10]
0045BFA3 8D45F4           lea eax,[ebp-$0c]
0045BFA6 BAFCBF4500       mov edx,$0045bffc
0045BFAB E8B88BFAFF       call @LStrCat3
0045BFB0 8B45F4           mov eax,[ebp-$0c]
0045BFB3 E8C810FDFF       call ShowMessage
Unit5.pas.40: end;
0045BFB8 33C0             xor eax,eax
0045BFBA 5A               pop edx
0045BFBB 59               pop ecx
0045BFBC 59               pop ecx
0045BFBD 648910           mov fs:[eax],edx
0045BFC0 68DABF4500       push $0045bfda
0045BFC5 8D45F0           lea eax,[ebp-$10]
0045BFC8 BA04000000       mov edx,$00000004
0045BFCD E8A288FAFF       call @LStrArrayClr
0045BFD2 C3               ret 
i nin ebx in sıfırlandıgı kod.

Kod: Tümünü seç

Unit5.pas.28: begin
0045BF4C 55               push ebp
0045BF4D 8BEC             mov ebp,esp
0045BF4F 33C9             xor ecx,ecx
0045BF51 51               push ecx
0045BF52 51               push ecx
0045BF53 51               push ecx
0045BF54 51               push ecx
0045BF55 51               push ecx
0045BF56 53               push ebx
0045BF57 56               push esi
0045BF58 33C0             xor eax,eax
0045BF5A 55               push ebp
0045BF5B 68EBBF4500       push $0045bfeb
0045BF60 64FF30           push dword ptr fs:[eax]
0045BF63 648920           mov fs:[eax],esp
Unit5.pas.29: i:=0;
0045BF66 33DB             xor ebx,ebx
Unit5.pas.30: ilevel:=0;
0045BF68 33F6             xor esi,esi
Unit5.pas.31: showmessage(intToStr(i));
0045BF6A 8D55FC           lea edx,[ebp-$04]
0045BF6D 8BC3             mov eax,ebx
0045BF6F E8F0C7FAFF       call IntToStr
0045BF74 8B45FC           mov eax,[ebp-$04]
0045BF77 E80411FDFF       call ShowMessage
Unit5.pas.32: for i := 0 to ilevel-1  do
0045BF7C 8BC6             mov eax,esi
0045BF7E 48               dec eax
0045BF7F 85C0             test eax,eax
0045BF81 7C07             jl $0045bf8a
0045BF83 40               inc eax
0045BF84 33DB             xor ebx,ebx
Unit5.pas.34: end;
0045BF86 43               inc ebx
Unit5.pas.32: for i := 0 to ilevel-1  do
0045BF87 48               dec eax
0045BF88 75FC             jnz $0045bf86
Unit5.pas.35: showmessage('cikti 1:'+IntToStr(i));
0045BF8A 8D55F4           lea edx,[ebp-$0c]
0045BF8D 8BC3             mov eax,ebx
0045BF8F E8D0C7FAFF       call IntToStr
0045BF94 8B4DF4           mov ecx,[ebp-$0c]
0045BF97 8D45F8           lea eax,[ebp-$08]
0045BF9A BA00C04500       mov edx,$0045c000
0045BF9F E8C48BFAFF       call @LStrCat3
0045BFA4 8B45F8           mov eax,[ebp-$08]
0045BFA7 E8D410FDFF       call ShowMessage
Unit5.pas.36: i:=0;
0045BFAC 33DB             xor ebx,ebx
Unit5.pas.40: showmessage('cikti 2:'+IntToStr(i));
0045BFAE 8D55EC           lea edx,[ebp-$14]
0045BFB1 8BC3             mov eax,ebx
0045BFB3 E8ACC7FAFF       call IntToStr
0045BFB8 8B4DEC           mov ecx,[ebp-$14]
0045BFBB 8D45F0           lea eax,[ebp-$10]
0045BFBE BA14C04500       mov edx,$0045c014
0045BFC3 E8A08BFAFF       call @LStrCat3
0045BFC8 8B45F0           mov eax,[ebp-$10]
0045BFCB E8B010FDFF       call ShowMessage
Unit5.pas.41: end;
0045BFD0 33C0             xor eax,eax
0045BFD2 5A               pop edx
0045BFD3 59               pop ecx
0045BFD4 59               pop ecx
0045BFD5 648910           mov fs:[eax],edx
0045BFD8 68F2BF4500       push $0045bff2
0045BFDD 8D45EC           lea eax,[ebp-$14]
0045BFE0 BA05000000       mov edx,$00000005
0045BFE5 E88A88FAFF       call @LStrArrayClr
0045BFEA C3               ret 
Kullanıcı avatarı
vkamadan
Kıdemli Üye
Mesajlar: 1935
Kayıt: 17 Mar 2004 03:52
Konum: Adapazarı
İletişim:

Re: FOR - DO nun çalışma anormalliği

Mesaj gönderen vkamadan »

merhaba @emin_as , @aslangeri' nin yazdığı açıklamadan anladığım kadarıyla bu olay delphiye özgü bir davranış biçimi, bir kural, stack analizini yaptığımızda adamlar yaklaşık 4byte gibi bir tasarruf yapabilmek için böyle bir uygulama getirmişler, yani biz LOOP değişkenini VAR bölümüne tanımlasakta FOR bölümüne gelene kadar stack' e alınmıyor, kullanıldığı anda alınıyor ve sonrasında kullanılabiliyor.
Yani bu bir bug değil sadece bir kural.
Volkan KAMADAN
www.polisoft.com.tr
Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3081
Kayıt: 17 Nis 2006 08:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Re: FOR - DO nun çalışma anormalliği

Mesaj gönderen sabanakman »

i değişkeni yerel bir değişken ve tanımlandığı anda sitemin durumuna göre rasgele bir değere sahip oluyor (sık yapılan bir hata da değişkenlere ilk değeri vermeden kullanmak, dikkat etmek gerek). Demekki for döngüsü 0'dan -1'e artarak saymaya çalıştığında o komutları hiç dikkate almıyor. Bu yapıdaki kodlamada i'nin değeri bana sınavda sorulsa direk 0 değerini alır diye hoplardım. Bunu öğrenmek iyi oldu.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .
Kullanıcı avatarı
aslangeri
Moderator
Mesajlar: 4322
Kayıt: 26 Ara 2003 04:19
Konum: Ankara
İletişim:

Re: FOR - DO nun çalışma anormalliği

Mesaj gönderen aslangeri »

arkadaşlar bu olay sadece for değişkeninde değil. tüm değişkenlerde aynı.
ağer bir değişkene değer atarsanız ama attığınız değeri kullanmazsanız delphi o atamayı derlemeye dahil etmiyor.
atamanın olduğu satıra preakpoint koyarsanız breakpoint in geçersiz olduğunu göreceksiniz. sebebi ilkili satırın derlemeye dahil edilmemesi dir ve sadece döngü değişkeninde değil tüm değişkenlerde aynıdır. Compiler mesajlarında görebilirsiniz "Hint :value assignet but newer used" şeklinde mesaj verir. bu o değişkenin set edildiği ancak kullanılmadığı anlamındadır. o komut derlemeye dahil edilmez.
Duyduğun Şeylerin Söylediklerim Olduğuna Eminim Ama
Anladığın Şeylerin Anlatmak İstediklerim Olduğuna Emin Değilim
Kullanıcı avatarı
sabanakman
Kıdemli Üye
Mesajlar: 3081
Kayıt: 17 Nis 2006 08:11
Konum: Ah bi Antalya olaydı keşke (Ankara)

Re: FOR - DO nun çalışma anormalliği

Mesaj gönderen sabanakman »

Sınav sorusunu zorlaştıralım o zaman :) .

Kod: Tümünü seç

var i,n,t:Integer; S:String;
begin
  S:=InputBox('Giriş','Sayı','');
  n:=StrToIntDef(S,-1);
  t:=0;
  for i:=0 to n do t:=t+i;
  ShowMessage(Format('i=%d , t=%d',[i,t]));
end;
kodlarında kullanıcı geçerli değer girerse i ve t değeri bellidir ama geçersiz ya da boş değer girerse i değeri ne göstercek? Bu soru bana sorulsa direk olarak 0 derdim ama değilmiş. Hem ne de olsa bütün kodlar derlemeye dahil ediliyor. Bu da çok ince bir ayrıntıymış, dikkat etmek gerek.
Şaban Şahin AKMAN
_________________
Derin olan kuyu değil kısa olan iptir. - .
Cevapla