C++ Nasıl Çalışır? Hafıza Ortamı

Giriş

Öncelikle C++ dilini veya bu katmandaki yazılım dillerini anlamak için belli başlı çalışma prensiplerini bilmek gerekiyor.

Her yazılım dili, tıpkı konuşma dillerindeki gibi belli gramerlere ve kurallara sahiptir. Bu gramer ve kurallar bütününe bu alanda syntax (sözdizimi) adı verilir.

Hafıza Ortamı

Yazılım dilleri çalışma zamanlarında verilere çok hızlı erişip, yazmak ve okumak için cihazınızın geçici hafızasını yani RAM’i kullanır.

Bunların geliştirici tarafında yazılan kısımlarına en çok “değişkenler” hakimdir.

Değişkenler belli veri tiplerinde tanımlanıp çalışma zamanında yazılımın hafızada, tanımlanan değişkene özel yer ayırıp üzerine kullanıcı veya geliştirici tarafından atanan değeri sonradan okuyabilmek için yazmasını yani elinizdeki değeri unutmamasını sağlar.

Veri tipleri demişken, hafıza ortamını C++ üzerinden anlattığımıza göre veri tiplerinin ne olduğunu, bunların neden var olduklarını ve tam olarak ne işe yaradıklarını anlayalım.

Veri Tiplerini anlamak.

Öncelikle özünde tüm veri tipleri hafızada sayısal değer tutar, metin verileri dediğimiz veriler kullanılan yazılım dili tarafından sayısal olarak okunup, yorumlanıp metne dönüştürülür.

Bir şeyler kodlarken bir değişken tanımladığımızda bu belirttiğimiz veri tipine göre hafızada kendisine yer ayıracaktır. Veri tiplerinin nihai amacı hafızada ne kadar yer kullanacağımızı belirtmektir.

Örnek olarak;

int Sayi = 5;

Integer, yani tam sayı tipinde bir değişken tanımladık.
Tam sayı değişkeni yazılım tarafından işleme koyulduğu an hafızada 4 byte’lık bir alan ayırır ve bu alana 5 değerini yazar.

Bu konuyu daha da açacak olursak hafızada adresleme işlemi hexadecimal yani onaltılık sayı sistemi ile yapılır.

Tanımladığımız değişken varsayımsal olarak ‭4E72F3‬ adresi üzerine ayrılıp o alana yazıldı. 4 byte olarak belirlediğimiz uzunluk ise;

4E72F3‬
‭4E72F4
‭4E72F5
‭4E72F6


olarak ayrılan adresin başlangıç adresinden itibaren hafızadan 4 adresi bu değişken için ayır demektir. Hafızadaki 1 adrese 0 ile 255 arası değer girilebilir. Bundan mütevellit 255 den büyük bir sayı yazmak istediğimiz için 1 adres bizim için yeterli olmayacaktır biz buraya 500 yazdığımızda yazılımımız bu 4 adresi kullanarak kendi içerisinde 500 sayısını bulmayı sağlayacak kombinasyonu oluşturup 4 adrese gerekli değerleri yazar ve okuma işlemi yapılırken de bu 4 adresin kombinasyonu şeklinde okunur.

Bu işleme de örnek verecek olursak 4 bytelık bir alana 4.294.967.296 farklı değer girilebilir bunun formülü ise bir adrese 0 ile 255 arası değer yani 256 adet değer girilebilmesi yani bunu 4 adrese tamamladığımızda 256*256*256*256 = 4.294.967.296 olmasıdır.

Bilinmesi gereken 2. şey de; Sayısal olarak kullanılan veri tipleri kendi içlerinde ikiye ayrılır: Signed (İmzalı) ve Unsigned (İmzasız)

Signed: Veri tipinin hafızada kapladığı alanı bölerek değerin negatif de olabilmesini sağlar, kullanılan veri tipleri çoğunlukla varsayılan olarak signed veri tipleridir.

Unsigned: İmzasız veri tipleri de hafızada aynı alanı kaplar fakat değerin negatif olamayacağını söyler bunun yazılıma kattığı avantaj ise örneğin -127 ve 128 sayı alabilen bir sbyte veri tipi unsigned olarak tanımlandığında 0 ve 255 arası değer alabilir. Aslında bu veri tipinin alabileceği değerler kümesinin boyutunu değiştirmez sadece koordinat’da başlangıç ve bitiş noktasını değiştirir. Bu sayede örnek olarak bir insanın yaşını tutmak istediğimiz değişken de signed yerine unsigned bir veri tipi kullanabiliriz çünkü bu değer hiçbir zaman negatif olmayacaktır. Bu bize küçük bir alanda büyük sayılar kullanabilme avantajı sağlar.

Bu bilgiler ışığında veri tiplerini inceleyebiliriz.

Birincil Veri Tipleri

byte (varsayılan olarak unsigned bir veri tipidir 0 <-> 255)
sbyte (yani signed byte -128 <-> 127)
char – unsigned char (yine byte eşliğinde metin karakteri girilebilen alandır olayı girilen karakterin byte karşılığını almasıdır.)

int unsigned int (tam sayı veri tipidir ayrımları vardır)
int16 – uint16 (2 bytelık tam sayı alanıdır 256*256 = 65.536 adet değer barındırabilir. Signed kısmı -32.768 <-> 32.767 unsigned kısmı 0 <-> 65.535)

int32 uint32 (4 bytelık tam sayı alanıdır çoğu dilde varsayılan olarak int’in karşılığı olarak bu verilir. 256*256*256*256 = 4.294.967.296‬ adet değer barındırabilir. Signed kısmı -2.147.483.648 <-> 2.147.483.647‬, unsigned kısmı 0 <-> 4.294.967.295‬)

int64 uint64 (8 bytelık tam sayı alanıdır hesaplamasını yapmaya üşendim.)

bool (hafızadaki olayının diğerlerinden pek bir farkı yok sadece yazılım tarafından kolay okunması için tanımlanmıştır sayı olarak 0 ve 1 değerlerini alır 0 hayır 1 evet demektir.

float ve double (ikisi de virgüllü sayıları barındırmak için kullanılır aralarındaki tek fark float virgülden sonrası daha kısa değerler için kullanılır hafızada kapladığı alan daha küçüktür (32 bit). Double (64 bit)

string (hafızadaki boyutu sabit değildir verilen metnin uzunluğu kadar byte olarak yer kaplar 30 karakter uzunluğunda bir metni 30 adet ardışık adrese (30 byte) boyutunda yazar ve bunları kombinasyonlu bir şekilde değil sıralı bir şekilde okuyarak her adresteki değerin karakter karşılığını bulup bir araya getirir.)

Sonuç

C++ üzerinden anlattığım üzere bir yazılımın hafıza kısmında çalışma prensibi bu şekildedir. Hatta kullandığımız programlara yapılan bir takım eklentiler, oynadığımız oyunlara yapılan hileler ve crackler bu olaya müdahil olarak yapılır. Örnek verecek olursak oynadığımız oyunlar da birer yazılımdan ibaret olduğu için o da kendi içerisinde sahip olduğu tüm verileri hafızada tutmak zorundadır hilelerin yaptığı şey hafızadaki doğru adresi bulup bu adres üzerindeki değeri değiştirmektir.

Eğer bir C++ kullanıcıysanız hafıza üzerinde ne gibi değişiklikler yapabileceğinizi, hafızaya nasıl erişebileceğinizi ve hafıza üzerinde ne tür yöntemlerle arama yapabileceğinizi öğrenebilmek için eski bir projemin kaynak kodlarına https://github.com/seukaiwokeo/Bear-Engine üzerinden erişebilirsiniz.