Menu

C# vs C++: Bellek, Performans, Oyun Geliştirme ve Öğrenme Eğrisi

C# çöp toplayıcılı, yönetilen bir dildir; C++ yerel koda derlenir ve bellek üzerinde elle kontrol verir. Bu farkın güvenlikte, performansta, oyun motorlarında, derleme modelinde ve öğrenme zorluğunda nasıl ortaya çıktığını görün.

Bu sayfada çalıştırılabilir editörler var - düzenle, çalıştır ve sonucu anında gör.

C# ve C++ bir harfi ve süslü parantezli sözdizimini paylaşır, ama farklı seviyelerde dururlar. C++ (1985) doğrudan makine koduna derlenir ve her nesnenin tam olarak nerede yaşadığını ve ne zaman öldüğünü kontrol etmenizi sağlar. C# (2002) ise .NET çalışma zamanının çalışma sırasında makine koduna çevirdiği bir ara dile derlenir ve belleği sizin için bir çöp toplayıcı geri alır. Aşağıdaki farkların neredeyse hepsi bu tek seçimden doğar.

Bir bakışta

C#C++
ÇalıştırmaYönetilen: IL, CLR tarafından JIT ile derlenirYerel: önceden makine koduna derlenir
BellekÇöp toplayıcıElle, RAII, akıllı pointer'lar
Pointer'larReferanslar; ham pointer'lar yalnızca unsafe koddaHer yerde ham pointer'lar ve referanslar
GüvenlikSınır denetimli diziler, sarkan referans yokSınır dışı erişimde, serbest bırakıldıktan sonra kullanımda tanımsız davranış
Derleme modeliProjeler ve assembly'ler, header yokHeader'lar, önişlemci, çeviri birimleri, linker
GenericsGenerics, bir kez denetlenir, çalışma zamanında çözülürTemplate'ler, derleme zamanında örneklenir
Standart kütüphaneBüyük: koleksiyonlar, HTTP, JSON, dosyalar, thread'lerDaha küçük: container'lar, algoritmalar, thread'ler
Derleme hızıHızlıBüyük kod tabanlarında yavaş
OyunlarUnity, GodotUnreal, çoğu şirket içi AAA motoru
Diğer başlıca kullanımlarWeb backend'leri, masaüstü, bulut, araçlarMotorlar, tarayıcılar, işletim sistemleri, gömülü sistemler, borsa işlemleri

Bellek: çöp toplayıcı ve RAII

C++'ta otomatik depolamalı bir nesne kapsam dışına çıktığında yok edilir ve destructor'ı tam o anda çalışır. Heap nesnelerinin sahibi akıllı pointer'lardır (std::unique_ptr, std::shared_ptr) ya da new ve delete ile elle yönetilirler. Resource Acquisition Is Initialization (RAII) denen bu kalıp, belleğin ve diğer her kaynağın belirlenimci biçimde temizlenmesini sağlar.

// C++
#include <memory>
#include <fstream>

void save() {
    std::ofstream file("log.txt");          // opened here
    auto buffer = std::make_unique<char[]>(4096);
    file << "saved\n";
}   // file closed and buffer freed here, in reverse order

C#'ta her sınıf örneği yönetilen heap'te yaşar ve çöp toplayıcı, ona hiçbir şey başvurmadığında onu daha sonraki bir anda serbest bırakır. Hiçbir zaman delete yazmazsınız ve hâlâ kullanımda olan bir şeyi asla serbest bırakamazsınız. Bellek halledilmiştir; GC'nin hemen halletmediği şey diğer kaynaklardır: dosyalar, soketler, veritabanı bağlantıları. Bunlar için C#'ta IDisposable ve bir bloğun sonunda Dispose'u çağıran using ifadesi vardır; destructor'a en yakın şey budur:

Çıktı:

open db
open cache
db <- SELECT 1
cache <- PING
close cache
close db
done

Fark şudur: C++'ta temizlik her yerel nesne ve akıllı pointer'ın sahip olduğu her nesne için kapsama bağlıdır; C#'ta ise bellek için otomatik, geri kalan her şey için isteğe bağlıdır (using ile). Bununla ilgili daha fazlası using ifadesi sayfasında.

Güvenlik: tanımsız davranış yerine istisnalar

C++'ta bir dizinin sonunu aşarak okumak tanımsız davranıştır: program çöp değer yazdırabilir, çökebilir ya da bozuk bellekle çalışmaya devam edebilir ve sonuç derlemeden derlemeye değişebilir. Aynı hata C#'ta tam ilgili satırda bir istisna fırlatır.

// C++: compiles, and the behavior is undefined
int scores[3] = {90, 85, 77};
int x = scores[5];   // reads whatever is in memory there

Çıktı:

Index 5 is outside an array of length 3
name was null

Bellek bozulması hatalarının tüm sınıfı (buffer taşmaları, serbest bırakıldıktan sonra kullanım, çift serbest bırakma, sarkan pointer'lar) güvenli C#'ta yoktur. C# kodunun daha hızlı yazılıp gözden geçirilmesinin büyük bir nedeni budur.

Pointer'lar ve unsafe kod

C#'ta pointer'lar vardır, ama yalnızca unsafe blokların içinde ve projenin <AllowUnsafeBlocks>true</AllowUnsafeBlocks> ile bunu açması gerekir. Yönetilen heap'teki nesneler çöp toplama sırasında yer değiştirebilir, bu yüzden adreslerini almadan önce onları fixed ile sabitlersiniz:

// C#, requires AllowUnsafeBlocks
unsafe
{
    int[] data = { 1, 2, 3 };
    fixed (int* p = data)
    {
        *(p + 1) = 20;   // data is now { 1, 20, 3 }
    }
}

Unsafe kod, yerel kütüphanelerle birlikte çalışma ve birkaç sıcak döngü için kullanılır. Bugün düşük seviye C# kodunun çoğu bunun yerine Span<T>, ref yerel değişkenleri ve stackalloc kullanır; bunlar sınır denetimlerini korurken pointer benzeri performans verir.

Performans

C++ tüm programı derleyiciye önceden verir ve çalışma zamanında hiçbir şey eklemez: çöp toplayıcı yok, JIT yok, siz istemedikçe sınır denetimi yok. Bu, her mikrosaniyenin ya da her baytın önemli olduğu ve duraklamaların kabul edilemediği yerlerde onu tercih edilen dil yapar.

C# güvenliğinin bedelini bir çalışma zamanı, başlangıçta JIT ısınması ve ara sıra GC duraklamalarıyla öder. Throughput açısından genellikle C++'a küçük bir fark içinde yaklaşır ve fark her .NET sürümüyle daraldı: profil yönlendirmeli optimizasyonla kademeli JIT, bellek ayırmalardan kaçınmak için struct'lar ve Span<T>, SIMD için donanım intrinsic'leri ve önceden tek bir yerel çalıştırılabilir dosyaya derleyen Native AOT. Web API'leri, araçlar ve iş mantığı için veritabanı ve ağ baskındır ve dil farkı nadiren görünür.

Oyun geliştirme: Unity ve Unreal

Çoğu insanın bu soruyla karşılaştığı yer burasıdır. Unity C# ile programlanır: oyun kodu, arayüz ve araçlar oyun nesnelerine bağlı C# sınıflarıdır, motorun çekirdeği ise C++'tır. Unreal Engine C++ ile yazılmıştır ve oyun kodu C++ artı Blueprints görsel betik sistemidir. Godot hem GDScript'i hem de C#'ı destekler.

Unity ile C# öğrenmek ve üzerinde yineleme yapmak daha hızlıdır; bağımsız ve mobil oyunlarda bu kadar yaygın olmasının nedeni budur. Unreal ve C++ AAA stüdyolarda standarttır ve her yerde motor programcıları C++ ile çalışır. Yaygın bir yol Unity ile başlamak, sonra Unreal'e ya da motor işine geçerseniz C++ öğrenmektir.

Derleme modeli

Bir C++ programı header'lara (.h, bildirimler) ve kaynak dosyalara (.cpp, tanımlar) bölünür. Önişlemci header'ları her kaynak dosyaya yapıştırır, her dosya ayrı derlenir ve linker sonuçları birleştirir. Template'ler onları kullanan her dosyada örneklenir; büyük C++ derlemelerinin yavaş olmasının nedenlerinden biri budur.

C#'ta bunların hiçbiri yoktur. Bir proje, birlikte bir assembly'ye (.dll) derlenen .cs dosyalarından oluşur; bildirim sırası ve dosya sırası önemli değildir ve bir dosyadaki tip, başka bir dosyadaki tipi include olmadan kullanabilir. Kütüphaneler NuGet paketleri olarak gelir. using yönergesi bir dosyayı değil bir namespace'i içe aktarır.

Fark edeceğiniz sözdizimi farkları

  • Nesneler. C++'ta auto p = std::make_unique<Player>(); ve p->Jump();; C#'ta var p = new Player(); ve p.Jump();. C# her şey için . kullanır.
  • String'ler. std::string değiştirilebilir bir değerdir; C# string'i değiştirilemez bir referans tipidir.
  • Çoklu kalıtım. C++ bir sınıfın birkaç sınıftan kalıtım almasına izin verir; C# bir temel sınıfa ve istenen sayıda interface'e izin verir.
  • Template'ler ve generics. C++ template'leri derleme zamanında kod üretimidir ve metaprogramlama yapabilir; C# generics'i açık kısıtlarla (where T : IComparable<T>) bir kez tip denetiminden geçer.
  • Standart kütüphane. C#'ınki HTTP, JSON, düzenli ifadeler, dosya G/Ç, sıkıştırma ve kriptografi içerir; C++'ta bunların çoğu üçüncü taraf kütüphanelerden gelir.

Hangisini öğrenmeli

Uygulamalar, web backend'leri, araçlar ya da Unity oyunları yapmak ve sonuçları hızlı görmek istiyorsanız C# öğrenin. Oyun motorlarını, grafiği, gömülü sistemleri, işletim sistemlerini, tarayıcıları ya da donanım seviyesinde kontrolün ve öngörülebilir gecikmenin asıl mesele olduğu her şeyi hedefliyorsanız C++ öğrenin. C# daha yumuşak bir ilk dildir; C++ ise ikinci dil olarak öğrenmeye değer, çünkü C# çalışma zamanının sizin için ne yaptığını öğretir.

Sıkça Sorulan Sorular

C# ile C++ arasındaki temel fark nedir?

C# yönetilen bir dildir: .NET çalışma zamanının JIT ile derlediği bir ara dile derlenir ve belleği bir çöp toplayıcı serbest bırakır. C++ doğrudan makine koduna derlenir ve nesnelerin ne zaman oluşturulup yok edileceğini siz kontrol edersiniz. Bu takas C++'a daha fazla kontrol ve öngörülebilirlik, C#'a ise daha fazla güvenlik ve daha hızlı geliştirme kazandırır.

C# C++'tan daha mı kolay?

Çoğu insan için evet. C#'ta elle bellek yönetimi, header dosyaları, güvenli kodda tanımsız davranış yoktur ve derleyici hataları daha anlaşılırdır. C++ daha büyük bir dildir ve derleyicinin yakalamadığı ince hatalar yapmanın daha çok yolu vardır: sarkan pointer'lar, buffer taşmaları, serbest bırakıldıktan sonra kullanım.

C++ C#'tan daha mı hızlı?

İyi yazılmış C++ genellikle daha hızlıdır ve daha önemlisi daha öngörülebilirdir, çünkü çöp toplayıcı duraklaması ve JIT ısınması yoktur. Modern C# bu farkı struct'lar, Span<T>, SIMD ve önceden (AOT) derleme ile daraltır ve iş uygulamalarında fark nadiren darboğazdır. Motorlar, sürücüler ve yüksek frekanslı işlem için C++ standart olmaya devam eder.

Oyun geliştirme için C# mı öğrenmeliyim, C++ mı?

İlk oyunlarınız için Unity (ya da Godot) ile C# daha hızlı geliştirip yayımlamanızı sağlar. Unreal Engine C++ (ve Blueprints) kullanır ve motor kodu yazan AAA stüdyolar C++ programcıları işe alır. Birçok geliştirici Unity ve C# ile başlar, motor seviyesinde çalışması gerektiğinde C++ öğrenir.

C#'ta pointer var mı?

Evet, AllowUnsafeBlocks proje ayarıyla açılması gereken unsafe kod bloklarının içinde. Sıradan C# referanslar kullanır; bunları çöp toplayıcı izler ve serbest bırakılmış belleği gösteremezler. ref, Span<T> ve stackalloc, pointer'a başvuracağınız çoğu durumu karşılar.

Coddy programming languages illustration

Coddy ile kodlamayı öğren

BAŞLA