assert
İfadesi ve enforce
- Bu programı
06:09
ve1:2
vererek çalıştırdığınızda hata atmadığını göreceksiniz. Buna rağmen, sonucun doğru olmadığını da farkedebilirsiniz:09:06'da başlayan ve 1 saat 2 dakika süren işlem 10:08'de sonlanır.
Görüldüğü gibi,
06:09
girildiği halde, çıkışa09:06
yazdırılmaktadır. Bu hata, bir sonraki problemde birassert
denetimi yardımıyla yakalanacak. - Programa
06:09
ve15:2
verildiğinde atılan hata, bizi şu satıra götürür:string zamanDizgisi(int saat, int dakika) { assert((saat >= 0) && (saat <= 23)); // ... }
Saat bilgisinin 0 ile 23 arasında bir değerde olmasını denetleyen bu
assert
denetiminin başarısız olması, ancak bu işlev programın başka yerinden yanlışsaat
değeriyle çağrıldığında mümkündür.zamanDizgisi
işlevinin çağrıldığısonucuYazdır
işlevine baktığımızda bir yanlışlık göremiyoruz:void sonucuYazdır( int başlangıçSaati, int başlangıçDakikası, int işlemSaati, int işlemDakikası, int bitişSaati, int bitişDakikası) { writef("%s'%s başlayan", zamanDizgisi(başlangıçSaati, başlangıçDakikası), daEki(başlangıçDakikası)); writef(" ve %s saat %s dakika süren işlem", işlemSaati, işlemDakikası); writef(" %s'%s sonlanır.", zamanDizgisi(bitişSaati, bitişDakikası), daEki(bitişDakikası)); writeln(); }
Bu durumda
sonucuYazdır
işlevini çağıran noktalardan şüphelenir ve onun programdamain
içinden ve tek bir noktadan çağrıldığını görürüz:void main() { // ... sonucuYazdır(başlangıçSaati, başlangıçDakikası, işlemSaati, işlemDakikası, bitişSaati, bitişDakikası); }
Çağıran noktada da bir sorun yok gibi görünüyor. Biraz daha dikkat ve zaman harcayarak sonunda başlangıç zamanının ters sırada okunduğunu farkederiz:
zamanOku("Başlangıç zamanı", başlangıçDakikası, başlangıçSaati);
Programcının yaptığı o dikkatsizlik nedeniyle
06:09
olarak girilen bilgi aslında09:06
olarak algılanmakta ve daha sonra buna15:2
süresi eklenmektedir.zamanDizgisi
işlevindekiassert
de saat değerini 24 olarak görür ve bu yüzden hata atılmasına neden olur.Burada çözüm, başlangıç zamanının okunduğu noktada parametreleri doğru sırada yazmaktır:
zamanOku("Başlangıç zamanı", başlangıçSaati, başlangıçDakikası);
Çıktısı:
Başlangıç zamanı? (SS:DD) 06:09 İşlem süresi? (SS:DD) 15:2 06:09'da başlayan ve 15 saat 2 dakika süren işlem 21:11'de sonlanır.
- Bu seferki hata,
daEki
işlevindekiassert
ile ilgili:assert(ek.length != 0);
O denetimin hatalı çıkması, da ekinin uzunluğunun 0 olduğunu, yani ekin boş olduğunu gösteriyor. Dikkat ederseniz,
06:09
ve1:1
zamanlarını toplayınca sonuç07:10
olur. Yani bu sonucun dakika değerinin son hanesi 0'dır.daEki
işlevine dikkat ederseniz, 0'ın hangi eki alacağı bildirilmemiştir. Çözüm, 0'ıncase
bloğunu daswitch
ifadesine eklemektir:case 6, 9, 0: ek = "da"; break;
Bu hatayı da bir
assert
sayesinde yakalamış ve gidermiş olduk:Başlangıç zamanı? (SS:DD) 06:09 İşlem süresi? (SS:DD) 1:1 06:09'da başlayan ve 1 saat 1 dakika süren işlem 07:10'da sonlanır.
- Daha önce de karşılaştığımız
assert
yine doğru çıkmıyor:assert((saat >= 0) && (saat <= 23));
Bunun nedeni,
zamanEkle
işlevinin saat değerini 23'ten büyük yapabilmesidir. Bu işlevin sonuna, saat değerinin her zaman için 0 ve 23 aralığında olmasını sağlayan bir kalan işlemi ekleyebiliriz:void zamanEkle( int başlangıçSaati, int başlangıçDakikası, int eklenecekSaat, int eklenecekDakika, out int sonuçSaati, out int sonuçDakikası) { sonuçSaati = başlangıçSaati + eklenecekSaat; sonuçDakikası = başlangıçDakikası + eklenecekDakika; if (sonuçDakikası > 59) { ++sonuçSaati; } sonuçSaati %= 24; }
Yukarıdaki işlevdeki diğer hatayı da görüyor musunuz?
sonuçDakikası
59'dan büyük bir değer olduğundasonuçSaati
bir arttırılıyor, amasonuçDakikası
'nın değeri 59'dan büyük olarak kalıyor.Belki de şu daha doğru bir işlev olur:
void zamanEkle( int başlangıçSaati, int başlangıçDakikası, int eklenecekSaat, int eklenecekDakika, out int sonuçSaati, out int sonuçDakikası) { sonuçSaati = başlangıçSaati + eklenecekSaat; sonuçDakikası = başlangıçDakikası + eklenecekDakika; sonuçSaati += sonuçDakikası / 60; sonuçSaati %= 24; assert((sonuçSaati >= 0) && (sonuçSaati <= 23)); assert((sonuçDakikası >= 0) && (sonuçDakikası <= 59)); }
Aslında
sonuçDakikası
hâlâ hatalıdır çünkü ona da 60'tan kalanı atamak gerekir. Ama şimdi işin güzel tarafı, artık bu işlevin hatalı saat ve dakika değerleri üretmesiassert
denetimleri nedeniyle olanaksızdır.Yukarıdaki işlevi örneğin
06:09
ve1:55
değerleriyle çağırırsanız,sonuçDakikası
'nı denetleyenassert
denetiminin hata vereceğini göreceksiniz. - Burada sorun, son hanenin 0 olmasından kaynaklanıyor. Son hane sıfır olunca onlar hanesini de katarak "on", "kırk", "elli", vs. diye okuyunca 0'a verilmiş olan "da" eki her durumda doğru çalışmıyor. Bu problemin çözümünü size bırakıyorum.