PDA

Tam Sürümünü Görmek İçin : Fark ve bağlılık


euler
04/11/2004, 01:21
C / C++ / C#
Bu dillerin birbirine bağlılığı nedir? Yani bu dillerden herhangi biri ile hiç uğraşmamış biri olarak aralarındaki bağlantı, benzerlik ya da farklar hakkında bilgi almak istiyorum. Örneğin c# öğrenmek için c ya da c++ öğrenmeye gerek var mıdır? Ya da c++ için c?


Arkantos
04/11/2004, 02:06
Bence bunların tek bağlılığı hepsinin bir C bulundurması :s008:

C#'ın diğerlerinden farkına gelince C++ dilinin geliştiricisi Bjarne Stroustrup'un ifadesiyle (http://www.research.att.com/~bs/bs_faq.html#Csharp) "birilerinin tekelinde olan bir işletim sistemiyle çok sıkı entegre olmuş bir dil olması" diyebiliriz. (Hamiş : Bu kısım yanlış anlaşılmasın. En başta BS C#'a bir programlama dili olarak hiç bir eleştirim yok diyor)

C# öğrenmek için c ya da c++ öğrenmeye gerek olduğunu tahmin etmiyorum. C++ öğrenmek için de C öğrenmeye gerek yoktur. C++'nin öğretilmesi hakkındaki modern görüş bunu savunur.

Ronin
04/11/2004, 19:31
C# apayrı bir dil, C++ ile de bu dil ile yapabildiğin her şeyi, hatta daha fazlasını yapabilirsin.

C# öğrenmek için C/C++ öğrenmeye gerek yoktur, fakat C++ için C öğrenmeyi şart koşuyorlar.

C# 'ı web uygulamalarındaki etkinliğinden ve kolay/derli toplu programlama açısından (programlamaya yeni başlayanlara) tavsiye ederim. Bu demek değil ki C# basit yada zor. Fakat söz dizimleri ve programlama yapısı bana daha yatkın geliyor... v.s. , v.s.

pulsar
06/11/2004, 18:49
C++ için C bilmek gerekir

acehreli
06/11/2004, 19:55
pulsar, C'deki olanaklarin buyuk bir kismi C++'ta da bulunur. Buradan ancak sunu cikartabiliriz: C++ ogrenen kisi, C'nin de buyuk bir kismini ogrenmis olur.

Ama neden C++ ogrenmeye dogrudan baslanilmasin ki? Karsilastigin C++ kitaplari "once C ogren, ondan sonra bunu oku" mu diyorlardi? Stroustrup'un kitabi once Kernighan&Ritchie'yi okumamizi mi onerir? (Hayir.)

Yoksa sen dizilerin, yapilarin, gostergelerin C'ye ozgu olduklarini mi dusunuyorsun? Onlarin hepsi C++'in da olanaklaridir. Neden onlari C++ dilini anlatirken tanitamayayim?

Bence sen de ilk paragrafta soyledigimi soylemek istiyorsun ama mantigi ters kuruyorsun. C++ ogrenen insan C'nin de cogunu ogrenmis olur. (C'nin son standardindan sonra artik bu da o kadar dogru degil ama neyse...)

Zaten dogru soru su olmalidir: C++ ogrenmeye baslayan kisi icin onceki C bilgisi iyi mi olur kotu mu; veya yarar mi getirir zarar mi?

C'nin buyuk bir kismi C++'ta da oldugu icin, o C++ olanaklarini ogrenmek icin ayrica zaman harcanmamis olur. Bu iyi... Ama C gibi dusunen kisi bu dusunce seklini C++'a aynen uygularsa kotu olur.

C++ ogrenecek olan kisi C++ ogrenir. Bunu yaparken C'de de bulunan olanaklarin bir cogunu da ogrenmis olur. Kisinin C bilmesine gerek yoktur.

Ali

Euclides
07/11/2004, 12:34
neden insanlar pointerlar üzerine kurulu bir dili(C+C++) ponitersız ifade etmeye kalklar,
assembly bilmeyen biri nasıl pointeri ifade edebilir ki ?

neden insanlar hep c ve c++ 2'ye ayırır ???
aralarındaki temel farkları yazsak ne kadar tutar ?
Buyrun yazın !
Herkes öğrensin herhalde benim gördüğüm 5-6 maddeden fazlası var ki bu kadar konuşuluyor...
(Tabii şimdi biri çıkıp C++ için OOP yazar bende C ile OOP yapıp morartabilirim,OOP yazacağına class tanımları farklarını anlatsın...)

karamemed
07/11/2004, 13:01
(Tabii şimdi biri çıkıp C++ için OOP yazar bende C ile OOP yapıp morartabilirim

Söylesene bana nasıl yapacaksın bunu? Morarmasak ta kızarırız bunu anlatılırsan. Tabii istersen önce OOP'den ne kastettiğini söyle. Kel, Kör, Topal bir C++ yapma bana.

pulsar
07/11/2004, 14:31
acehreli esazinda az cok ayni noktadayiz ama C bilmeden ++ a gecmek biraz zor oluyor o nedenle c bilmek faydali olur.
Söylesene bana nasıl yapacaksın bunu? Morarmasak ta kızarırız bunu anlatılırsan. Tabii istersen önce OOP'den ne kastettiğini söyle. Kel, Kör, Topal bir C++ yapma bana.

Esazinda Euclides biraz asiriya gitmis yazarken ama dogrudur yapilabilir bu ama once enteresan yapilar yazmak gerekiyor yoksa yapilmaz degil. Akli cok kurcaladigindan C++ diye bir dil var zaten.

Euclides biliyorsun ben de asm ile cok ilgili biriyim ve C dilini assemblyden sonra ogrendim (dogrusu yazik ettim biraz kendime) ama bu kadar pointer takintili olma birak adamlar ust duzey dille rahat is gorsunler senle biz de ayri kulvarlarda pointeri registerda unutup neden derleyicinin owerflow salakligina dustugunden bahsedelim. Ilgilenen pratikten is gorsun biz onlarin eliti olalim. :)

karamemed
07/11/2004, 22:35
Esazinda Euclides biraz asiriya gitmis yazarken ama dogrudur yapilabilir bu ama once enteresan yapilar yazmak gerekiyor yoksa yapilmaz degil. Akli cok kurcaladigindan C++ diye bir dil var zaten.

Meselede bu zaten. Niçin OOP bir dili ben C ile örterim deniliyor. Zaten tüm yazılan programlar sonunda makine diline çevriliyor. Bu OOP ile yazılan bir programın doğrusal bir dille de(sanırım doğrusal deniliyor idi) yazılabileceği anlamına geliyor.

Peki insanlar niçin OOP diye bir şey düşünmüş. OOP'nin C gibi dillere göre bir çok artıları ve eksileri var. C dilini çok güçlü bir dildir. Ama bu c ile OOP yazarım gibi çok büyük bir yükün altına girmeye sebep olmasa gerek. pulsar'ın da dediği gibi C++ dili niçin var ki zaten? C++ çok iyi tasarlanmış bir dil. şahsen ben büyük bir proje için C ile uğraşacağıma C++'ı tercih ederim. Çünkü büyük projelerde nesnelerle uğraşıp tasarım yapmak, kodlama yapmak daha kolay, daha okunur oluyor bana göre. Zaten C++ bunun için C'den daha üst düzey bir dil.

acehreli
08/11/2004, 09:16
Euclides, gostergeler (isaretciler veya'pointer'lar) gercek yasamda karsimiza cikan kavramlarin bilgisayardaki karsiliklaridir. Gostergeler, 'dolayli yoldan bahsetmek' kavramina karsilik gelirler. Assembly dilinde yazmaclarla (register) ifade ediliyor olmalari onlari assembly dilinin olanaklari yapmaz.

Tanidik bir ornek olmasi acisindan futboldan ornek vermek gerekirse, "para atisi hakem tarafindan yapilir" ifadesindeki "hakem", belirli bir macta maci yoneten gercek bir kisiyi gosterir. "Hakem" aynidir ama her macta onun gosterdigi gercek insan farklidir.

C++'ta referanslar da bu kavrami ifade edebildikleri icin, kullanimi daha zor ve hatalara daha acik olan gostergelerden daha cok kullanilirlar ve onerilirler. Yoksa C++'i bu "dolayli yoldan gosterme" kavrami olmadan anlatamayiz. Zaten gostergeler (veya referanslar) cok basit olan ornek programlar disinda hemen hemen her programda karsimiza cikarlar.

OOP konusunda pulsar ve karamemed'in soylediklerine katiliyorum: Tabii ki C ile de nesneye yonelik programlama yapilabilir. Ilk C++ derleyicisi olan cfront, C++ kodunu C'ye cevirir ve ondan sonra C olarak derlerdi. Yani cfront'un yazdigini insanlar da yazabilecegine gore, C ile de nesneye yonelik program yazilabildigi gorulur.

Gunumuzun en iyi C++ derleyicilerinden birisi olan Comeau (http://www.comeaucomputing.com/) bile hAlA C++ kodunu C'ye cevirir ve bilgisayarda bulunan bir C derleyicisi ile derler. (Bunu bugunku C++ ile yapabiliyor olmasi inanilir gibi degil aslinda :) )

Ben de bir kac sene once C ile turden bagimsiz (generic) topluluk denemeleri yapmistim (C++'in sablonlari gibi):

http://groups.yahoo.com/group/cdili/files/C%20Programciligi/Turkce%20Dokumanlar/Program%20Kodlari/Turden%20Bagimsiz%20Programlama/

Sonucta her ust duzey dil makine koduna (assembly demiyorum) cevrildigine gore, insanlar isleri dogrudan makine kodunda bile yapabilirler.

Tabii arac kullanabilen yaratiklar oldugumuz icin, o araclar sayesinde hep isleri kolaylastirma yoluna gideriz. Ust duzey diller de bu yuzden vardirlar. Konuyu dagitma pahasina, assembly dilinin en ustun dil oldugunu savunanlara karsi kullanilan cok bildik bir savunmayi hatirlatmak istiyorum: bilgisayarin anladigi tek dil makine kodudur; assembly dili kullanarak ust duzeye cikiyorsak, orada durmamali ve daha da ust duzeylere cikabilmeliyiz.

Euclides; ben C++'la C'nin farklarini dogada gordugumuz cogu sisteme benzetiyorum. Ozlerinde cok az sayida fark bulunan iki sistem, buyuk olcekte karsilastirildiklarinda tamamen ilgisiz olabiliyorlar.

C++'in C'de bulunmayan olanaklari, onu beklendiginden cok daha farkli bir hale getiriyor. Bu yuzden artik C'nin gelismisi olarak degil de bambaska bir dil olarak kabul ediliyor. Yazilan kitaplarin buyuk bir cogunlugunun da bunlari C ve C++ olarak ikiye ayirmalari bunun bir gostergesidir. Zaten "C/C++" kitaplarini ciddiye bile almiyoruz.

C++'in aykiri durumlari (exceptions) bunun en guzel ornegidir. Asagidaki C programinda 'ikinci' adli islevin islenecegine kesin gozuyle bakariz. Cunku C bize boyle guvenilir bir program akisi sunar:


void islev()
{
birinci();
ikinci();
}


[Not: Evet, 'birinci'nin islenmesi sirasinda 'exit' veya 'long_jump' gibi, bu dogal program akisini bozan islevlerle de karsilasabiliriz. Ancak bunlar C programcisinin programi tasarlarken dusundugu seyler degildir. Bir C programcisi bu isleve baktigi zaman, dogal olarak 'birinci'den donuldugunde 'ikinci'nin de islenecegini dusunur ve kodunu ona gore yazar.]

Aykiri durumlar gibi tek bir olanak dile eklendigi anda bu tur bir dusunce tarzi tamamen uygunsuz olmaya baslar. Bir C++ programcisi, yukaridaki gibi bir islev yazdigi zaman, 'birinci'nin islenmesi durumunda bir aykiri durum atilabilecegini ve 'ikinci'nin islenmeyecek olabildigini her zaman icin aklinda tutmak zorundadir.

Eger 'ikinci' kaynak temizligi yapan onemli bir islevse, yukaridaki kod bir C++ programinda acikca bir hatadir! Ne kadar carpici degil mi? C icin cok dogal olan bir kod, C++ icin hatali oluyor...

Iste benim en sevdigim "C ile C++ farki" ornegi:


void islev()
{
Tur * p = malloc(/* ... */);
/* bir is yap */
free(p);
}


C'den gelen programci, bu C kodunu kendi bildiklerini C++'a uygulayarak soyle yazar:


void islev()
{
Tur * p = new Tur;
/* bir is yap */
delete p;
}


Eger 'bir is yap' kisminin islenmesi sirasinda bir aykiri durum atilirsa 'delete p' satiri islenemez ve bellek kaybedilir.

Bence bu, bir C++ olanaginin C'ce dusunmeyi ogrenmis bir programciya oynadigi oyunu cok guzel bir sekilde gosterir.

Buna bir de C++ olanaklarinin birbirleriyle etkilesimlerini eklersek, iki dil birbirlerinden daha da ayrilirlar.

Ali

Euclides
08/11/2004, 17:57
Euclides, gostergeler (isaretciler veya'pointer'lar) gercek yasamda karsimiza cikan kavramlarin bilgisayardaki karsiliklaridir. Gostergeler, 'dolayli yoldan bahsetmek' kavramina karsilik gelirler. Assembly dilinde yazmaclarla (register) ifade ediliyor olmalari onlari assembly dilinin olanaklari yapmaz.

Öncelikle asm'de pointerlar registerlarla ifade edilmek zorunda değildir.

Bu sözlerini pek çok programlama kitabındaki "Pointer=değişeknin hafızadaki adresi/yeri/konumu vb...." sözle benzetiyorum.

Bİr an için bunun doğru olduğunu düşünelim
PID:123'deki char x'in &x=56789 olsun
PID:124'deki char y'i' &y=56789 olsun

tanıma göre bu 2 değişken aynı adresi kullanıyorlarmış gibi gözüküyor.
FAKAT bu yanlıştır, doğal olarak tanımda yanlıştır.

Peki bu "56789" hafıza adresi değilse nedir ?
bu sorunun cevabı IA-32 Manuals->Protected mode memory managment'da var
ancak bu yazıyı anlayabilmek için asm gerekli İŞTE bu yüzden ben asm öğrenilmesi zorunlu bir dildir diyorum.

Tabii arac kullanabilen yaratiklar oldugumuz icin, o araclar sayesinde hep isleri kolaylastirma yoluna gideriz. Ust duzey diller de bu yuzden vardirlar. Konuyu dagitma pahasina, assembly dilinin en ustun dil oldugunu savunanlara karsi kullanilan cok bildik bir savunmayi hatirlatmak istiyorum: bilgisayarin anladigi tek dil makine kodudur; assembly dili kullanarak ust duzeye cikiyorsak, orada durmamali ve daha da ust duzeylere cikabilmeliyiz.

bak:Unreal Tournament 2004
demek ki hala inline asm bir şecenek değil bir zorunluluk....
2...
asm'de diğer dillerde(c&c++) kullanamadığmız programlama tekniklerini kullanabiliriz.
buna örnek vermiştim
ceviz.net->doc->assembly

C++'in aykiri durumlari (exceptions) bunun en guzel ornegidir. Asagidaki C programinda 'ikinci' adli islevin islenecegine kesin gozuyle bakariz. Cunku C bize boyle guvenilir bir program akisi sunar:

void islev()
{
birinci();
ikinci();
}


[Not: Evet, 'birinci'nin islenmesi sirasinda 'exit' veya 'long_jump' gibi, bu dogal program akisini bozan islevlerle de karsilasabiliriz. Ancak bunlar C programcisinin programi tasarlarken dusundugu seyler degildir. Bir C programcisi bu isleve baktigi zaman, dogal olarak 'birinci'den donuldugunde 'ikinci'nin de islenecegini dusunur ve kodunu ona gore yazar.]

Aykiri durumlar gibi tek bir olanak dile eklendigi anda bu tur bir dusunce tarzi tamamen uygunsuz olmaya baslar. Bir C++ programcisi, yukaridaki gibi bir islev yazdigi zaman, 'birinci'nin islenmesi durumunda bir aykiri durum atilabilecegini ve 'ikinci'nin islenmeyecek olabildigini her zaman icin aklinda tutmak zorundadir.

yazının bundan sonraki kısmı bu örneğe dayandığı için buna cevap yazmak yetiniyorum.

Bunlar yazdıklarım hem c++ hem de c için geçerlidir.

hadi bir exc. yapalım ve neticeyi beraber görelim
x=1;
x--;
y=120;
z=y/x; //DIIIt 0'la bölüm hatası
x++; //bu satıra asla ulaşılamadı

pek ne oldu ?
div/idiv komutu 0'la bölüm algıladı ve int0'i çağırdı.
işletim sistemi çekirdeği programı sonlandırdı, bizde pek ünlü "Bu program geçersiz bir işlem yürütü ve kapatılacak" mesajını aldık :)

div->Int0->Kernel->Sonlandır

Structed Exception Handling (SEH)
çok ünlü
"try","catch","throw","__try","__finally","__except"
ancak aşağıdaki şekilde programlanırsa kod akmaya devam eder aksi taktirde
process sonlandırlır
__try{
x=1;
x--;
y=120;
z=y/x; //DIIIt 0'la bölüm hatası Windows' SEH'i gördü derleyicimizin "gizli" SEH fonskiyonuna gitti
x++; //bu satıra asla ulaşılamadı
}__finally{
x=10; //bu satıra ulaştı
}
... //normal akış....
....

bu da ortada hiç bir oyun olmadığını çok iyi gösterir....
(tabii kullan MFC/VCL sonra hata mesajları c++'a atfet...)

acehreli
08/11/2004, 21:18
Euclides, C ve C++ programcilari gostergeleri aslinda adres degerinden biraz daha ust duzey kavramlar olarak kullanirlar. ++p yaptigimiz zaman "p'nin degeri 1 (veya baska bir miktar) artti" diye degil, "p simdi bir sonraki nesneyi gosteriyor" diye dusunuruz.

Herhangi bir nedenden dolayi gostergelerin degerlerine bakmak zorunda bile olsa, hicbir C veya C++ programcisi, protected mode gibi isletim sistemi ile islemci arasindaki iliskileri goze almaz. Nasil daha da ileri giderek belirli bir nesnenin belirli bir anda hangi fiziksel bellek cipinde oldugu bilgisine bakmiyorsak, isletim sistemi ve/veya islemcinin gercek bellege erismek icin yaptigi donusumlere de bakmayiz.

Bunlari, C veya C++'a yeni baslamis olanlari uyarmak icin soyluyorum. Anlattigin alt duzey adres ve/veya gosterge bilgileri C ve C++ programcilari icin onemli degildir. Biz programlarimizi yazarken dillerin getirdikleri ust duzey olanaklari kullaniriz. C ve C++ programcilarinin gostergeleri anlamalari icin adres hesaplarina bakmaya ihtiyaclari yoktur. Gosterge, nesneleri dolayli yoldan ifade etmek icin kullandigimiz ust duzey bir kavramdir. Bu kadari yeterlidir ve zaten ancak bu kadari kullanilir.

Unreal Tournament 2004'in konuyla ne ilgisi var? Benim assembly'nin gereksiz oldugunu soyledigimi dusundugun icin ornek olarak mi veriyorsun? Eger oyleyse, ben boyle bir sey soylemedim. "Konuyu dagitma pahasina" verdigim ek bilgiyi dikkate alma. Konudan ayrilirken amacim, assembly'yi diger dillere ustun tutan zihniyetin kendisiyle celistigini gostermekti.

Bir daha: Eger makine kodununun ustune cikmissak, orada durmamiz icin bir neden yoktur; *ayni nedenlerle* assembly'nin de ustune cikabiliriz. Boyle yaptigimizda gercek programciliktan uzaklasmis olmayiz. Yaptigimiz sey, dogamiza uygun bir sekilde, arac kullanmaktan baska bir sey degildir.

Tabii ki her dilin yeri ayridir. Ben bitirme odevimden bu yana hic assembly yazmadim, ama calistigim projelerde assembly yazanlar oldu. Assembly gayet saglikli bir sekilde yasamini surduruyor; kimse merak etmesin.

birinci/ikinci ornegine yaptigin yorumlari yalnizca ek bilgi olsun diye veriyorsun degil mi? Yoksa beni yanlis anladigini dusunecegim. Ornegin ben "C'de bir sonraki satira her zaman erisilir" demedim. Gosterdigin sifirla bolme hatasini da "'exit' veya 'long_jump' gibi, bu dogal program akisini bozan islevlerle de karsilasabiliriz" ifadesinin icinde sayabilirsin.

Soylemek istedigim, "ardarda gelen iki ifade" kadar basit bir kavramin C ve C++ programlari yazarken ne kadar buyuk bir farklilik getirdigiydi.

Structured Exception Handling'in konuyla ne ilgisi var? C'de oyle bir sey mi var? C programcilari onun sunuldugu ozel ortamlarda onu kullanarak mi programliyorlar?

C++ dili, C programcisina cok degisik sayida oyunlar oynar. Bunlardan bir tanesi, yukarida verdigim new/delete kullanimindaki hatadir. C'den gelen cogu programci ya bu hatayi hicbir zaman gormez, ya da benim basima geldigi gibi, bes yildan sonra gorur.

Tartismayi dagitmamak icin, kendi savundugum gorusleri bir kere daha ozetleyecegim:

1) Gosterge kavramini anlamak icin assembly bilmeye gerek yoktur.

2) C ve C++, kitaplarinin yazarlarinin da dusundukleri gibi, ayri dillerdir. Bunun en guzel gostergelerinden birisi, art arda gelen iki ifadeye bu iki dil programcilarinin ne kadar farkli yaklastiklaridir.

Ali

Euclides
09/11/2004, 15:44
birinci/ikinci ornegine yaptigin yorumlari yalnizca ek bilgi olsun diye veriyorsun degil mi? Yoksa beni yanlis anladigini dusunecegim. Ornegin ben "C'de bir sonraki satira her zaman erisilir" demedim. Gosterdigin sifirla bolme hatasini da "'exit' veya 'long_jump' gibi, bu dogal program akisini bozan islevlerle de karsilasabiliriz" ifadesinin icinde sayabilirsin.

ne yazık ki düşüncen doğru
anlamadım. ???
excp.'lerde onu bütünleştiremiyorum ???

Euclides
09/11/2004, 15:46
Soylemek istedigim, "ardarda gelen iki ifade" kadar basit bir kavramin C ve C++ programlari yazarken ne kadar buyuk bir farklilik getirdigiydi.

Structured Exception Handling'in konuyla ne ilgisi var? C'de oyle bir sey mi var? C programcilari onun sunuldugu ozel ortamlarda onu kullanarak mi programliyorlar?

windows da evt...

acehreli
10/11/2004, 10:51
Aykiri durumlar (exceptions) konusuna girmemin nedeni, Euclides'in C++'in C'ye eklenmis bes alti tane olanaktan olustugunu soylemesiydi. Onun ifadesine bakinca; C++'in aslinda daha becerikli C gibi oldugu gibi bir anlam cikartmistim. Bu anlamla alinca; sanki C'den ogrendigimiz gibi yazabilir ve gerektikce de C++'in getirdigi olanaklari kullabilirmisiz gibi dusunuluyor gibi gelmisti.

Bense o bes alti tane olanagin yalnizca "ek olanak" olmadiklarini ve kendi programlarimizda kullanmasak bile yazis tarzimizi tamamen degistirdiklerini gostermek icin, aykiri durumlarla ilgili bir ornek vermistim.

Aslinda asagida soyleyecegim seylerin ozeti su: Salt aykiri durum olanagi bile, C++'in C gibi yazilmasini olanaksiz kilar. C gibi yazilan C++ hatalarla doludur. C programcilari kendi dusunce tarzlariyla baslayarak C++ programlari yazamazlar. Once dusunce tarzlarini degistirmeleri gerekir. (Onceki C bilgisinin C++'ta gucluk cikarttigi gorusunun temeli budur.)

Bunun en guzel orneklerinden birisi, cozumu C++ camiasini bes yil kadar ugrastiran bir iddiadir: Tom Cargill, ortaya aykiri durumlarin sanildigi kadar ise yarar olmadiklari ve yarardan cok zarar getirdikleri yolunda bir iddia atar: (Su anda o makalenin icerigini tam olarak hatirlamiyorum, ama buna benzer bir seydir.)

http://www.awprofessional.com/content/images/020163371x/supplements/Exception_Handling_Article.html

Su iki program bu konunun ozunu bence guzel olarak gosteriyor.

Not: Bununla ilgili daha ayrintili bilgi icin aykiri durumlarin babasi Herb Sutter'i okuyabilirsiniz. Ozellikle su, tam bu konu ile ilgilidir:

http://www.gotw.ca/gotw/008.htm

Elimizde iyi bir C programcisi (ornegin ben :) ) tarafindan C'de yazilmis bir YIgIt (stack) gerceklemesi olsun:

Not: Bu programlar gereginden uzun oldular. Aslinda konunun ozu C programindaki Yigit_cikart ve C++ programindaki Yigit::cikart islevlerinde goruluyor. Acelesi olanlar yalnizca o islevlere bakabilirler :)


#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

typedef struct Yigit
{
int * nesneler;
int buyukluk;
int tepe;
}
Yigit;

void Yigit_kur(Yigit * yigit)
{
yigit->nesneler = 0;
yigit->buyukluk = 0;
yigit->tepe = -1;
}

void Yigit_boz(Yigit * yigit)
{
free(yigit->nesneler);
}

void Yigit_buyult(Yigit * yigit)
{
yigit->buyukluk = ((yigit->buyukluk == 0)
? 2
: yigit->buyukluk* 3 / 2);

yigit->nesneler = realloc(yigit->nesneler,
yigit->buyukluk * sizeof(int));
}

/* push */
void Yigit_ekle(Yigit * yigit, int sayi)
{
++yigit->tepe;

if (yigit->tepe == yigit->buyukluk)
{
Yigit_buyult(yigit);
}

yigit->nesneler[yigit->tepe] = sayi;
}

/* pop */
int Yigit_cikart(Yigit * yigit)
{
assert(yigit->tepe >= 0);
--yigit->tepe;
return yigit->nesneler[yigit->tepe + 1];
}

int main()
{
int i = 0;
int const adet = 3;
Yigit yigit;

Yigit_kur(&yigit);

for (i = 0; i != adet; ++i)
{
printf("Ekliyorum: %d\n", i);
Yigit_ekle(&yigit, i);
}

for (i = 0; i != adet; ++i)
{
printf("Cikarttim: %d\n", Yigit_cikart(&yigit));
}

Yigit_boz(&yigit);

return EXIT_SUCCESS;
}


Kendim yazdigima gore, yukaridaki programin hatasiz oldugunu dusundugume inanabilirsiniz. (valgrind da hatasiz oldugunu ve bellek kayiplari bulunmadigini soyluyor.)

Cok guzel... Simdi bu programcinin ayni isi C++'la yapmak istedigini ve yigitini kullanici turleriyle de kullanabilmek icin C++'in sablon olanagini kullandigini varsayalim. Yani artik yalnizca int yigiti degil, herhangi bir turun yigiti olabilecek. (Burada haksizlik yaptigimi dusunmeyin ama; int yerine 'void *' kullanarak ve biraz daha emek harcayarak C yigitini da herhangi bir turle kullanabilirdik.)


#include <algorithm>
#include <assert.h>

template <class T>
class Yigit
{
T * nesneler_;
int buyukluk_;
int tepe_;

void buyult()
{
int const eski_buyukluk = buyukluk_;
buyukluk_ = ((buyukluk_ == 0)
? 2
: buyukluk_ * 3 / 2);

T * yeni_nesneler = new T[buyukluk_];
std::copy(nesneler_,
nesneler_ + eski_buyukluk,
yeni_nesneler);

delete[] nesneler_;
nesneler_ = yeni_nesneler;
}

public:

Yigit()
:
nesneler_(0),
buyukluk_(0),
tepe_(-1)
{}

~Yigit()
{
delete[] nesneler_;
}

// push
void ekle(T const & nesne)
{
++tepe_;

if (tepe_ == buyukluk_)
{
buyult();
}

nesneler_[tepe_] = nesne;
}

// pop
T cikart()
{
assert(tepe_ >= 0);
--tepe_;
return nesneler_[tepe_ + 1];
}
};

#include <iostream>

using std::cout;

int main()
{
int const adet = 3;
Yigit<int> yigit;

for (int i = 0; i != adet; ++i)
{
cout << "Ekliyorum: " << i << '\n';
yigit.ekle(i);
}

for (int i = 0; i != adet; ++i)
{
cout << "Cikarttim: " << yigit.cikart() << '\n';
}
}



Bu da cok guzel ve yine hem bana hem de valgrind'a gore hatasiz... Ancak bu program, sablonda T ile belirtilen Yigit parametresinin bir kullanici turu oldugunda ve o turun kullanimi (ornegin kopyalanmasi) sirasinda bir aykiri durum atilmasi durumunda hatali olmaya baslayacaktir.

Bunun nedeni, C++ programinin C gibi dusunulerek yazilmis olmasidir. Programci C'den bildigi yontemleri uygulamis ve hatasiz oldugunu sandigi bir C++ programi yazmistir.

Burada C++'ta islemeyen yontem, henuz tepedeki nesnenin cagirana saglikli bir sekilde dondurulecegi kesin olmadan tepe_ ogesinin eksiltiliyor olmasidir. cikart islevi icinde

--tepe_;

dedigimizde, tepedeki nesne artik Yigit'in gozunde yigittan cikartilmistir. Ancak,

return nesneler_[tepe_ + 1];

satirinda donus degeri cagiranin ortamina kopyalanirken bir aykiri durum atilirsa, tepedeki nesne artik kaybedilmis olacaktir.

C++ programcisi, arayuzleri boyle olasiliklari goze alarak yazmak zorundadir. Boyle bir dusunce tarzi C'de yoktur. Bazi ortamlarda sunulan Structured Exception Handling'i (SEH) C'nin yaygin bir olanagi olarak sayamiyorum. SEH'in kullanildigi durumlarda da bunun ozel durumlarla sInIrli oldugunu, ve C programcilarinin alistiklari dusunce tarzlarini biraktiracagini dusunmuyorum. (Cevremde ve nette gordugum C programlarinda onlarin bu sekilde yazildiklarini dusundurecek seyler gormedim.)

C++ programinin dogru yazilabilmesi icin tek cozum, Yigit sinifinin arayuzunun degistirilmesidir. cikart islevi deger donduremeyecegine gore, ekle ve cikart islevlerine ek olarak, tepedeki nesneye erisim saglayan 'tepe' adli bir islevin de yazilmasi gerekir.

Yalnizca degisiklikleri veriyorum:


template <class T>
class Yigit
{

/* ... */

// pop
void cikart()
{
assert(tepe_ >= 0);
--tepe_;
}

T & tepe()
{
return nesneler_[tepe_];
}

// Bu da sabit Yigit nesneleri icin
T const & tepe() const
{
return nesneler_[tepe_];
}
};

/* ... */

int main()
{

/* ... */

int const tepedeki = yigit.tepe();
yigit.cikart();
cout << "Cikarttim: " << tepedeki << '\n';
}
}



Sonucta, aykiri durumlar C'ye eklenen olanaklar degil; C++'ca dusunmeyi C'ce dusunmekten ayiran cok onemli unsurlardir.

Daha once soyledigim birinci/ikinci ornegi de bunun baska bir gostergesidir. Islemler aykiri durum atabilecekleri icin, C++'ta hemen hemen hicbir kod satirinin isleneceginden emin olamayiz. Bu, temizlik isleriyle ilgili olan satirlarda cok buyuk onem tasir.

Onun icin, C++'ta temizlikle ilgili olan isler kod satirlarina yazilmazlar. O isler, cagrilacaklari kesin olarak bilinen bozucu islevler (destructors) icinde yapilmak zorundadirlar. Iste bu da C programcisinin C++'a gectiginde alismak zorunda oldugu buyuk bir degisikliktir.

Kodun icine serpistirilmis fopen/fclose, malloc/free, lock/unlock, vs. gibi kullanimlar geride birakilmalidir.


Cok konustum... Aslinda sonucta soylemek istedigim bu kadar uzun degil: Ek olanaklar yalnizca ek olmayabilirler.

Ali

Ayrica not: Aslinda ek olanaklarin dilin karmasikligini dogrusal olarak arttirmadiklarini da dusunuyorum ama artik onu soylemek istemiyorum ;) Yani bes alti ekin etkisi, karmasikligi karesini almak gibi etkileyebilir. (Bunlari soylemedim :) )

Euclides
10/11/2004, 13:10
Bu da cok guzel ve yine hem bana hem de valgrind'a gore hatasiz... Ancak bu program, sablonda T ile belirtilen Yigit parametresinin bir kullanici turu oldugunda ve o turun kullanimi (ornegin kopyalanmasi) sirasinda bir aykiri durum atilmasi durumunda hatali olmaya baslayacaktir.

bütün yazını üşenmedim satır satır satır okudum
savın "aykırı durum" üzerine kurulu. peki nedir bu "aykırı durum"
bunu sormamın temel sebebi ikimizinde farklı şeylerden bahsetiğini düşünüyor olmam.
Bunu yaratan bir kod örneği verirsen senin neden bahsetiğini anlayabilirim.
beklenmeyen bir aykırı durum meydana gelir -> program sonlanır.
(en azından benim anladığım bu)


Ve ayıca bu bile sadece 1 madde olabilir.

Hepsini başka bir topic altında yazalım.
Sayıyı görelim :)

acehreli
11/11/2004, 02:09
Bu tartismayi "Aykiri durumlarin C++'in C'den farkliligina etkisi" adindaki yeni konuya tasidim.

Ali

ummaz
17/11/2004, 23:53
sizinle olmaktan mutluluk duyuyorum..