[Blog] C#'taki Yapı ve Sınıf Nesneleri Nerede Yaratılıyor?
Pek çok C# programcısının sınıf ve yapı kavramlarıyla stack ve heap kavramlarını yanlış bir biçimde ilişkilendirdiğini görüyorum. Örneğin, “yapı nesneleri stack’te sınıf nesneleri heap’te tutulur” biçiminde yanlış anlaşılmaya yol açacak bilgiler veren yerli ve yabancı çok sayıda yazı ve makaleyle karşılaştım. Konuya biraz açıklık getirmek istiyorum.
[Makale] UNIX/Linux Sistemlerinde Dosya Betimleyicilerinin Anlamı
UNIX/Linux sistemlerinde her prosesin proses tablosu yoluyla erişilen bir dosya betimleyici tablosu (file descriptor table) vardır. Dosya betimleyici tablosu bir gösterici dizisi biçimindedir. Betimleyci tablo içersindeki her gösterici açılmış bir dosyanın bilgilerinin tutulduğu ve ismine dosya nesnesi (file object) denilen bir veri yapısını gösterir. open fonksiyonundan elde edilen dosya betimleyicisi (file descriptor) prosesin dosya betimleyici tablosunda bir indeks belirtmektedir.
[Makale] UNIX/Linux ve Windows Sistemlerinde Proseslerin Çalışma Dizinleri
Her prosesin bir çalışma dizini (current working directory) vardır. UNIX türevi sistemlerde prosesin çalışma dizini proses fork fonksiyonuyla yaratılırken üst prosesten alınır. exec işlemleri sırasında da yaratılmış olan prosesin çalışma dizini değişmez. Yani bu sistemlerde bir proses bir alt proses yarattığında yaratılan alt prosesin çalışma dizini üst prosesin çalışma dizini ile aynı olacaktır. Windows sistemlerinde de alt prosesin çalışma dizini onu yaratan proses tarafından CreateProcess API fonksiyonu çağrılırken belirlenir. Her iki grup işletim sisteminde de prosesin çalışma dizini daha sonra belirli sistem fonksiyonlarıyla değiştirilebilmektedir.
[Makale] Portable Executable Dosya Formatında CLI Metadata Tablolarının Organizasyonu
.NET, Mono ve Rotor gibi CLI (Common Language Infrastructure) standartlarına uygun ortamlardaki assembly dosyaları PE (Portable Executable) dosya formatını kullanmaktadır. PE dosya formatı Micosoft’un 32 ve 64 bit Windows sistemlerinde kullandığı genel amaçlı çalıştırılabilir (executable) bir formattır. Bu format tıpkı UNIX/Linux sistemlerinde kullanılan ELF (Executable and Linkable Format) gibi bölümlerden (sections) oluşur. Bölümlerin içerisinde programın yüklenmesi ve çalıştırılabilmesi için gerekli bilgiler vardır.
[Blog] Bilgisayar Bilimleri İçin İki Kategorizasyon Sistemi
Bir nesne ya da olgunun bütün içerisindeki yerinin belirlenmesi ve diğer nesne ya da olgularla ilişkilerinin betimlenmesi sürecine kategorizasyon deniyor. Kategorizasyonun sentezlemeyi artırarak öğrenmeye katkıda bulunduğunu söyleyebiliriz. Sentezleme süreci de anlamsal bellek (semantic memory) içeriğindeki ilişkileri sağlamlaştırıyor olabilir.
Pek çok C# programcısının sınıf ve yapı kavramlarıyla stack ve heap kavramlarını yanlış bir biçimde ilişkilendirdiğini görüyorum. Örneğin, “yapı nesneleri stack’te sınıf nesneleri heap’te tutulur” biçiminde yanlış anlaşılmaya yol açacak bilgiler veren yerli ve yabancı çok sayıda yazı ve makaleyle karşılaştım. Konuya biraz açıklık getirmek istiyorum.
Bir nesne ya da olgunun bütün içerisindeki yerinin belirlenmesi ve diğer nesne ya da olgularla ilişkilerinin betimlenmesi sürecine kategorizasyon deniyor. Kategorizasyonun sentezlemeyi artırarak öğrenmeye katkıda bulunduğunu söyleyebiliriz. Sentezleme süreci de anlamsal bellek (semantic memory) içeriğindeki ilişkileri sağlamlaştırıyor olabilir.
Bana çok sorulan sorulardan biri de budur. Diyorlar ki, “yahu neden global değişkenlere varsayılan bir değer (tipik olarak sıfır değeri) atanıyor da yerel değişkenlere atanmıyor? Bu hak mı, adalet mi?”. Özellikle C# ve Java gibi içerisine değer atanmamış değişkenlerin kullanılmasına izin verilmeyen dillerde çalışanlar yerel değişkenlerin otomatik olarak sıfırlanmamasından memnun değiller.
Nedense dizinlerin erişim hakları pek çok UNIX/Linux programcısına karmaşık geliyor. Geçen haftalarda bu konuyla ilgili birkaç soruyla karşılaştım. Genel bir açıklama yaparsam tereddütleri olanların kafalarındaki soru işaretlerini belki biraz azaltabilirim diye düşünüyorum.
C#’taki foreach döngülerinde kullanılan döngü değişkenlerinin neden read-only olduğu bana çok soruluyor. Soranların çoğu döngü değişkeninin read-write olması durumunda işlevselliğin artacağını iddia ediyorlar. Örneğin onlara göre eğer foreach döngü değişkeni read-only olmasaydı bir dizinin tüm elemanları belirli bir değerle şöyle doldurulabilirdi:
foreach (int x in a)
x = val;
i, j, k, l, m, n döngü değişkeni olarak en çok tercih edilen isimler. Nerede bir for döngüsü görseniz döngü değişkeninin ismi büyük olasılıkla ya i’dir ya j’dir ya da k’dır. Hiç düşündünüz mü neden a değil, b değil, c değil de i, j, k? Eski kuşak programcılar (yani bayağı bir eskiler) bunun nedenini iyi bilirler. Dolayısıyla bu açıklamayı onlar için değil yeni kuşak yazılımcılar için yapacağım.
restrict gösterici kavramı resmi olarak C99 ile standartlara girdi. C++ standardizasyon komitesi restrict göstericilere hiç sıcak bakmadı. C++0x’te de restrict göstericilerin eklenmesine yönelik bir işaret yok.
Yıllar önceydi. Bir arkadaşımın kodunu inceliyordum. Kodunda max ismini verdiği bir değişken vardı. Ben de doğal olarak bu değişkenin en büyük değeri tuttuğunu sanarak kodu anlamlandırmaya çalıştım. Ancak birşeyler tam yerine oturmuyordu bir türlü. Meğerse arkadaşım başlangıçta en büyük değeri bulup kullanırken sonra en küçük değerin bulunup kullanılması gerektiğini düşünerek algoritmasını değiştirmiş. Fakat değişkenin ismini değiştirmemiş. Düşünebiliyor musunuz, bir değişken var, ismi max fakat bu aslında en küçük değeri tutuyor :-).
Pek çok C# programcısının using namespace direktifinin kullanımını pek iyi bilmediğini görüyorum. Bu konuda bazı açıklamalar yapayım dedim. Ancak bu yazıda extern alias ve using alias direktifleri üzerinde durmayacağım. Bunlara ilişkin de bir makale yazmayı planlıyorum.
Öncelikle using namespace direktifinin, isim alanlarının ilk elemanları olacak biçimde -eğer varsa- extern alias direktiflerinden sonra belirtilmek zorunda olduğunu anımsatayım. Örneğin aşağıdaki bildirim geçersizdir:
Gecenin bir yarısı üzerinde çalıştığınız programı tam da derleyip çalıştıracakken telefonunuz çalsa ne yapardınız? Derlemenin sonucunu mu beklerdiniz, yoksa bir donanım kesmesi oluşmuşçasına telefona mı koşardınız? İşte geçen gün ben derlemenin sonucunu beklemeyi tercih ettiğim için çalan telefona yetişemedim. Fakat sonra içimi bir endişe kapladı. Yoksa gecenin bu saatinde kötü bir haberin iletilmesi için mi aranmıştım?..
Bu problemde programcı içi dolu bir şekli taşımak istemektedir. Taşıma sırasında eski şekli silerek yenisini çizer. Fakat şekli taşırken titreme (flickering) oluşmaktadır... Bu biçimdeki titreme probleminin nedeni silinecek bölgenin büyük bir kısmının önce zemin rengiyle hemen ardından da asıl renkle boyanmasıdır. (Problem genel olmasına karşın ben burada kod örneklerini C/C++ ile API düzeyinde değil C# ile .NET üzerinde vereceğim. Hani benim de C# kullanmaya gönlüm razı olmuyor. Fakat belki böylece daha fazla kişiye hitap edebilirim :-) )
POD (Plain Old Data) C++’ta ayrıntıları pek bilinmeyen karışık bir konudur. Pek çok dökümanda POD terimi geçtiği halde pek az C++ programcısının bu konuyu tam olarak bildiğini görüyorum.
C’de genel olarak (ister int, long gibi aritmetik türden olsun, isterse dizi ya da yapı türünden olsun) her türden nesnenin byte’ları bellekte ardışıl bir biçimde tutulmaktadır. Nesnenin adresini alarak o adresten itibaren sizeof değeri kadar byte’ı memcpy gibi bir fonksiyonla bir alana aktarıp aynı biçimde geri alırsak eski nesneyi elde ederiz. C standartları bunu garanti etmektedir. Örneğin:
Doğal dillerdeki kurallar matematiksel anlamda kesin değildir, bunların istisnaları çoktur. Zaten bizi herhangi bir şey öğrenirken bezdiren şeylerden biridir istisnalar. Örneğin İngilizce’de daha yüksek demek için high sıfatı higher haline, tall sıfatı taller haline geliyor. Pek çok sıfatın bu biçimde "er" eki aldığını görüyoruz. Fakat bu kesin bir kural mı? Hayır, bunun pek çok istisnası var. Örneğin, (her nedense) kötü bad olduğu halde daha kötü için worse kullanılıyor. (Ana dil gibisi var mı? Hepimiz kırmızı için kıpkırmızı, mavi için masmavi denildiğini biliriz. Bunun bir kuralının olup olmadığını sorgulamamışızdır. Zaten umurumuzda da değildir. Kimse kırmızı için maskırmızı demez.)
Aşağıdaki ifadeyi inceleyiniz:
b = ++a + foo() * bar();
pek çok C ve C++ programcısı işlemlerin aşağıdaki sırada yapılacağının garanti olduğunu sanıyor:
Son yıllarda özellikle Internet siteleri yoluyla köşe dönme öyküleri bizim gibi psikoekonomik (!) yapısı bozuk olan toplumlarda sanrısal patlamalara yol açtı galiba. Gün geçmiyor ki (lafın gelişi tabi) parlak fikir sahibi bir girişimci kapımızı çalmasın. Ampulü yananın fellik fellik ortak aradığı bir dönemden geçiyoruz.
CSD C ve Sistem Programcıları Derneği