> C ve C++ nin içerisindeki C arasındaki farklar: >> C dilinde 'bool' veri tipi mevcut değil. C99 ile '_Bool' veri tipi eklenmiş fakat bu da arka planda 'int' veri tipini kullanmakta. Fakat C++ dilinde 'bool' bir veri tipi. Her iki dilde de bunlar bir byte yer kaplamaktalar. >> C dilinde karşılaştırma ve mantık operatörlerinin geri dönüş değerlerinin türleri 'int' veri tipiyken, C++ dilinde bunlar 'bool' veri tipindedirler. >> C dilinde kullanılan 'NULL' aslında bir makrodur ve '0' rakamına tekabül eder. C++ dilinde ise 'nullptr', 'nullptr_t' türündendir. >> C dilinde aritmetik türleri göstericilere atayabiliyoruz. Benzer şekilde göstericileri de aritmetik türlere atayabiliyoruz. >>> 'zero' değerine sahip bir değişkeni göstericilere atadığımız zaman, ilgili gösterici 'NULL' değerini almaktadır. >>> 'non-zero' değerine sahip bir değişkeni göstericilere atadığımız zaman, ilgili gösterici 'Non-NULL' değerini almaktadır. >> C++ dilinde ise aritmetik türleri göstericilere, göstericileri de aritmetik değerlere atayamıyoruz. Bunun tek istisnası, sadece Legacy C++ döneminde kullanılan, "int* ptr = 0" şeklindeki bir atamadır. Modern C++ döneminde ise bunun yerini 'nullptr' almıştır. Burada unutulmaması gereken, istisnai durumun sadece '0' rakamının göstericilere atanması içindir. '0' rakamı hariç diğer değişkenlerin göstericilereatanması hem legacy C++ hem de modern C++ döneminde sentaks hatasıdır. >> C dilinde '(void *)' türünden '(T *)' türüne otomatik dönüşüm vardır. Örtülü bir dönüşümdür(implicit conversion) (bkz. 'malloc()'). Fakat C++ dilinde böyle bir örtülü dönüş olmadığı için, kullanıcı, harici olarak ilgili '(void *)' türünden nesneyi '(T *)' türünden nesneye 'cast' etmelidir. Ama 'C-Style' cast işlemi ile ama C++ dilinde mevcut olan 'static_cast' vs. gibi diğer araçlar ile. * Örnek 1, #include using namespace std; int main() { int* ptr = nullptr; ptr = 0; // LEGAL, SADECE legacy C++ dönemindeki kodlarda kullanılmalıdır. cout << "ptr:" << ptr << "\n"; ptr = 200; // invalid conversion from ‘int’ to ‘int*’ [-fpermissive] void* vPtr = ptr; // LEGAL int* iPtr = vPtr; // invalid conversion from ‘void*’ to ‘int*’ [-fpermissive] return 0; // Örnektende görüldüğü üzere, // i. 'void*' -> 'T*' : Örtülü dönüşüm yoktur. // ii. 'T*' -> 'void*' : Örtülü dönüşüm VARDIR. } >> C++ dilinde farklı adres türleri arasında örtülü dönüşüm olmadığı için bu durum sentaks hatasıdır. Bu durumda kullanıcı, yukarıdaki 'casting' araçlarını kullanarak harici bir dönüşüm yapmalıdır. Fakat C dilinde böyle bir örtülü dönüşüm vardır. * Örnek 1, // Some codes here... int main() { int x = 10; int* xPtr = &x; char* cPtr = xPtr; // C++ dilinde bu çağrı sentaks hatasıyken, C dilinde geçerlidir. } >> 'const' anahtar sözcüğünün kullanımındaki farklılıklar: >>> C dilinde 'const' anahtar sözcüğü ile bildirilen fakat ilk değer verilmeyen, yani 'uninitialize' durumda olan, değişkenler iki farklı değer ile hayata gelirler; >>>> 'static' ömürlü değişkenler ise hayata '0' değeri ile gelirler. >>>> 'automatic' ömürlü değişkenler ise hayata 'garbage-value' ile gelirler. >>> C++ dilinde ise 'const' anahtar sözcüğü ile nitelenen değişkenler ilk değer almak zorundadır. Ömür kategorilerinin burada bir önemi yoktur. Aksi halde sentaks hatasına neden olur. Yani nesnenin kendisi 'const' ise ilk değer almak zorundadır. * Örnek 1, // Some codes here... int main() { const int* ptr; // C++ dilinde bu geçerlidir. Çünkü 'ptr' değişkeninin kendisi 'const' değildir. Sadece // gösterdiği değişken 'const' statüsündedir. //int* const ptr; // İşte bu durumda sentaks hatası olmuş olur. // Çünkü 'ptr' in kendisi 'const' durumdadır. } >>> NE C DİLİNDE YAZARKEN NE DE C++ DİLİNDE YAZARKEN 'const' ANAHTAR SÖZCÜĞÜ İLE NİTELENDİRİLMİŞ BİR DEĞİŞKENİ / NESNEYİ, 'C-style Casting' ile DEĞİŞTİRME GİRİŞİMİNDE BULUNMAMALIYIZ. BÖYLE BİR GİRİŞİMDE BULUNMAK SENTAKS HATASIDIR. SENTAKS HATASINI BY-PASS EDEREK GİRİŞİMDE BULUNDUĞUMUZ ZAMAN, 'Tanımsız Davranış'A NEDEN OLMUŞ OLURUZ. >>> C dilinde 'const T*' türünden 'T*' türüne örtülü bir dönüşüm vardır, sentaks hatası değildir. Fakat C++ dilinde böyle bir örtülü dönüşüm olmadığı için sentaks hatasıdır. >>> C dilinde 'const int' türünden bir değişkeni, 'Constant Expressions' alan noktalarda kullanamıyoruz. Velev ki ilgili 'const int' türden değişkeni bir 'integral literals' ile hayata getirmiş olsak bile. Örneğin, bu türden bir değişkeni dizi boyutu olarak veya 'switch-case' merdiveninde kullanamıyoruz. Fakat C++ dilinde böyle bir kullanım legaldir, sentaks hatasına neden olmaz. * Örnek 1, // Some codes here... int foo(); int main() { const int x = 10; // Burada 'x' değişkeni, 'integral literals' ile hayata gelmiştir. const int y = foo(); // Derlenme sırasında 'y' değişkeninin değeri bilinemememektedir. // Burada 'y' değişkeni, 'integral literals' ile hayata gelmiyor. int a[x]; // C dilinde sentaks hatasıdır. (Variable Array Length konusu hariç) int b[x]{}; // C++ dilinde legaldir. } >>> Eğer bir isim, >>>> Farklı kaynak dosyalarında kullanılmasına rağmen, aynı varlığa hitap ediyorsa, bu isim 'external linkage' haldedir. >>>>> C ve C++ dilinde bir isim ve/veya fonksiyon 'global namespace' alanında kullanılmışsa, bu isim 'external linkage' durumundadır. İsmin 'const' ile nitelenmesi durumunda ilgili isim C++ dili kurallarına göre artık 'internal linkage' durumuna geçmiştir fakat C dili için böyle bir kural söz konusu değildir. >>>> Farklı kaynak dosyalarında kullanılmasına rağmen, birbirinden farklı varlıklara da hitap ediyorsa, bu isim 'internal linkage' haldedir. >>>>> C ve C++ dilinde bir isim ve/veya fonksiyon 'global namespace' alanında kullanılmışsa, bu isim 'external linkage' durumundadır. İsmin 'static' ile nitelenmesi durumunda ilgili isim her iki dil kurallarına göre artık 'internal linkage' durumuna geçmiştir. >> 'enums' kullanımındaki farklılıklar: >>> C dilinde numaralandırma sabitlerinin türleri 'int' türüne eşitken, C++ dilinde ya elemanların veri tiplerine göre yada kullanıcının atadığı 'T' veri tipi türündedir. >>> C dilinde aritmetik türlerden 'enum' türlere, 'enum' türlerden aritmetik türlere ve farklı 'enum' türleri arasında otomatik bir dönüşüm vardır. Fakat C++ dilinde sadece 'enum' türlerden aritmetik türlere otomatik bir dönüşüm vardır. Bu da beraberinde bir takım handikaplar getirmektedir. Bunları örtbas etmek için de Modern C++ ile dile 'enum class' türler eklendi. Artık 'enum class' türleri kullanacağız. >> 'user-defined types' kullanımlarındaki farklılıklar: >>> C dilinde bu tip türler, ki bunlar 'struct', 'unions' ve 'enum' şeklindedir, yalnız başına kullanılamıyorlar. Yani sadece etiket ismi ile birlikte kullanılamazlar. Fakat C++ dilinde sadece etiket ismi ile birlikte kullanılabilirler. * Örnek 1, // Some codes here... struct Data{ // Etiket ismi 'Data' int mx; }; typedef struct Data_{ int my; }DataTwo; int main() { Data myData; // C dilinde bu sentaks hatasıdır. Legal hale getirmek için ya 'struct' anahtar sözcüğü ile // birlikte ya da 'typedef' yaparak kullanmalıyız. Fakat C++ dilinde geçerlidir. Ne 'struct' // anahtar sözcüğüne ne de 'typedef' kullanımına gerek yoktur. struct Data myData; // C diline göre legal kullanım bu şekildedir. DataTwo myDataTwo; // C diline göre legal bir kullanım şeklidir. } * Örnek 2, // Some codes here... struct Data{ // Etiket ismi 'Data' int Data; // Veri elemanının ismi de 'Data' }; int main() { struct Data Data; // C dilinde bu tip bir kullanım geçerlidir. // C++ dilinde ise 'name look-up' kuralları gereği geçersizdir. Data: // goto- label // C dilinde bu tip bir kullanım da geçerlidir. // C++ dilinde ise 'name look-up' kuralları gereği geçersizdir. } >> C dilinde 'struct' yapı türünün en az bir elemanı olmak zorunda. Fakat C++ dilinde böyle bir zorunluluk yoktur. İçi boş bir 'struct' de kurabiliriz. >> Fonksiyon bildirimleri ve tanımlamalarındaki farklılıklar: >>> C dilinde 'implicit int' kullanımı C99 standartları ile sentaks hatasına neden olsa da, geçmişe dönük uyumluluktan dolayı, ana akım derleyiciler tarafından geçerli kabul edilmekte. Fakat C++ dilinde bu kullanım sentaks hatası. * Örnek 1, // Some codes here.. foo(); // Fonksiyonun bildiriminde geri dönüş değerinin türü yazılmamasına rağmen, 'implicit int' gereği, // derleyici tarafından 'int' türü yazılmakta. fuu() {} // Fonksiyonun tanımında geri dönüş değerinin türü yazılmamasına rağmen, 'implicit int' gereği, derleyici // tarafından 'int' türü yazılmakta. fpp(x,y) { return x+y; } // Fonksiyonun tanımında, geri dönüş değerinin ve fonksiyon parametrelerinin türleri yazılmamasına rağmen, // 'implicit int' gereği, derleyici tarafından 'int' türü yazılmakta. int main() {} * Örnek 2, #include fpp(x,y) { return x+y; } int main() { /* # OUTPUT # main.c: In function ‘fpp’: main.c:11:1: warning: type of ‘x’ defaults to ‘int’ [-Wimplicit-int] main.c:11:1: warning: type of ‘y’ defaults to ‘int’ [-Wimplicit-int] fpp(2,3) : 5 */ printf("fpp(2,3) : %d", fpp(2,3)); } >>> C dilinde yapılan fonksiyon bildirimlerinde/tanımlamalarında, parametre parantezinin içerisine 'void' anahtar sözcüğünün yazılması, ilgili fonksiyonun parametre almayacağını söylemektedir. Haliyle bu fonksiyonlara parametre geçmek sentaks hatasıdır. Fakat bu parantezlerinin içerisinin boş bırakılması, fonksiyon parametreleri hakkında bilgi verilmediği anlamına gelir ki bu tip fonksiyonlara parametre geçebiliriz. Sentaks hatası oluşturmaz. Ama C++ dilinde bu parantezlerinin içinin boş bırakılması veya 'void' anahtar sözcüğünün yazılması aynı anlama gelmekte olup, tercihen 'void' yazmalıyız. Yani bu parantezlerin içini boş bırakmamalıyız. İllaki bir şeyler yazmalıyız. >>> C dilindeki fonksiyon bildirimlerinde, fonksiyon parametrelerine isim vermek zorunda değiliz. Fakat fonksiyon tanımlamalarında isim vermek zorundayız. Ama C++ dilinde ne fonksiyon bildirimlerinde ne de fonksiyon tanımlamalarında, fonksiyon parametrelerine isim vermek zorunda değiliz. Sadece 'Function Overload Resolution' için kullanılır bu taktik. >>> C dilinde, geriye değer döndüren bir fonksiyonun bloğunda 'return' anahtar sözcüğü ile değer döndürmemek, legal bir davranıştır. Sentaks hatasına neden olmaz. Sadece bu fonksiyonu çağırıp da geri dönüş değerini kullanmamız 'Tanımsız Davranış' a neden olur. Fakat C++ dilinde bu tip fonksiyonların bloğunda 'return' kullanılmaması sentaks hatasıdır. NOT: C++ DİLİNDE 'main()' FONKSİYONUNUN GERİ DÖNÜŞ DEĞERİ 'int' OLMAK ZORUNDA FAKAT C DİLİNDE BÖYLE BİR ZORUNLULUK YOKTUR. 'void' DE OLABİLİR 'double' DA OLABİLİR. NOT: C++ DİLİNDE VE C99 STANDARTLARI SONRASINDA C DİLİNDE 'main()' FONKSİYONUNUN BLOĞU İÇERİSİNDE 'return 0;' DEYİMİ YAZILMAZ İSE DERLEYİCİ KENDİSİ YAZIYOR. >>> 'implicit-function-declaration' : aşağıdaki örneği inceleyin, * Örnek 1, // Some code here... // int func(); //(2) Derleyici tarafından varsayım üzerine yazılan fonksiyon bildirimi. int main() { func(); //(1) C derleyicisi burada 'func' ismini bulamayacağı için, kendisi varsayımda bulunarak, yukarıdaki // fonksiyon bildirimini yapıyor. func(2, 5); //(3) Bu 'func' fonksiyonuna parametre geçebiliriz. Çünkü fonksiyon parametleri hakkında bilgi // verilmemiştir. double dVal = func(); //(4) Bu 'func' fonksiyonunun geri dönüş değerini kullanabiliriz fakat bu durum 'Tanımsız Davranış' // oluşturur. // Yukarıdaki senaryo C99 ile sentaks hatası olmasına rağmen, geriye dönük uyumluluktan dolayı hala // geçerlidir. Fakat C++ dilinde bu durum direkt sentaks hatasıdır. } * Örnek 2, #include int main() { /* # OUTPUT # main.c:13:2: warning: implicit declaration of function ‘func’ [-Wimplicit-function-declaration] 13 | func(); | ^~~~ main.c: At top level: main.c:16:1: warning: return type defaults to ‘int’ [-Wimplicit-int] 16 | func() | ^~~~ func() was called. */ func(); } func() { printf("func() was called."); } >> 'string literals' kullanım farklılıklar: >>> Hem C dilinde hem de C++ dilinde 'string literals' değiştirme girişiminde bulunmak 'Tanımsız Davranışa' a neden olur. >>> C dilinde bir 'string literals' in türü 'char[n]' türünden.Fakat C++ dilinde ise bu türler, 'const char[n]' türünden. Eğer bir 'string literals' işleme sokarsak, örneğin bir fonksiyona argüman olarak geçersek, 'array-decay' den dolayı sırasıyla 'char[n]' => 'char*' ve 'const char[n]' => 'const char*' şeklinde bir dönüşüm gerçekleşir. Aşağıdaki örneği inceleyelim. * Örnek 1, // Some codes here... int main() { char* xPtr = "Ahmet"; // Bu ifade C diline göre legal, C++ diline göre illegal bir deyimdir fakat C dilinde de // kullanılmamalıdır. const char* yPtr = "Ahmet"; // Bu ifade ise hem C dilinde hem de C++ dilinde olması gereken kullanımı göstermektedir. // Yukarıdaki her iki gösterici üzerinden "Ahmet" yazısını DEĞİŞTİRME GİRİŞİMİNDE BULUNMAMALIYIZ. // 'Tanımsız Davranış' meydana gelecektir. } >> 'character literals' kullanım farklılıkları: >>> C dilinde bu tip literaller, ki bunlar 'A' şeklindeki karakter sabitleridir, 'int' veri türündendir. Fakat C++ dilinde bu tip literallerin türü 'char' veri türündendir. >> 'char' türden veri tutan bir diziye 'string literal' atanması durumundaki farklılıklar: >>> Aşağıdaki örneği inceleyin, * Örnek 1, // Some codes here... int main() { char str[] = "mert"; // Normal şartlarda yukarıdaki dizinin türü 'char[5]' ve eleman sayısı ise beştir. char strTwo[4] = "memo"; // C++ diline göre illegal, C diline göre legal. Fakat yukarıdaki gibi köşeli parantezlerin arasında, // 'string literals' eleman sayısından daha düşük bir eleman sayısı yazarsak, 'strTwo' isimli diziyi // 'null-terminated-string' olarak ele alamayız. Artık 'strTwo' isimli dizinin elemanları sırasıyla // 'm', 'e', 'm' ve 'o' dan oluşmaktadır. C++ dilinde ise yukarıdaki gibi bir değer verme sentaks // hatasıdır. } >> 'Value-Category' konusundaki farklılıklar: >>> C++ dilinde '++' ve '--' operatörleri ön-ek olarak kullanıldığında, geri döndürdüğü değer 'L-Value Expression' kategorisine girer. İlgili operatörler son-ek olarak kullanılması durumunda, geri döndürdüğü değer 'R-Value Expression' kategorisindedir. Fakat C dilinde bu iki operatör her zaman için 'R-Value Expression' kategorisinde değer döndürür. >>> C++ dilinde ',' operatörü kullanıldığında, geri döndürdüğü değer 'L-Value Expression' kategorisine girer. Fakat C dilinde geri dönen değerin kategorisi 'R-Value Expression'. >>> C++ dilinde 'ternary operator' kullanıldığında, geri döndürdüğü değer 'L-Value Expression' kategorisine girer eğer bütün argümanları 'L-Value Expression' ise. Eğer bir tanesi bile 'R-Value Expression' ise döndürdüğü değerin kategorisi 'R-Value Expression' şeklindedir. Fakat C dilinde geri dönen değerin kategorisi 'R-Value Expression'. >>> Hem C++ dilinde hem de C dilinde '+' operatörünün geri dönüş değerinin kategorisi 'R-Value Expression'. >> '+' ve '-' operatörlerinin C ve C++ dillerindeki kullanımları, * Örnek 1, ifadenin türünü 'PR-Value' haline getirir. //.. int main() { int x = 10; x...; // 'x' ismi burada 'L-Value' şeklinde. +x...; // 'x' ismi artık 'PR-Value' şeklinde. y...; // 'y' ismi burada 'L-Value' şeklinde. -y...; // 'y' ismi artık 'PR-Value' şeklinde. } * Örnek 2, 'integral-promotion' a neden olur. //.. int main() { char c = 10; c...; // 'c' isminin türü 'char'. +c...; // 'c' ismi bir işleme sokulduğundan bu ifadenin türü artık 'int'. }