[Makale] C’nin Standart Dosya Fonksiyonlarının Uyguladığı Tamponlama Mekanizması
Standart C fonksiyonlarını kullanmadan bir dosyanın her byte’ı üzerinde sırasıyla işlem yapmak isteyelim. Herhalde ilk akla gelecek yöntem doğrudan işletim sisteminin sistem fonksiyonlarını çağırmak olacaktır. Örneğin UNIX/Linux sistemlerinde dosyayı read fonksiyonuyla (Windows sistemlerinde ReadFile fonksiyonuyla) byte byte aşağıdaki gibi okuyabiliriz:
int fd;
ssize_t result;
unsigned char ch;
if ((fd = open("test", O_RDONLY)) < 0) {
perror("open");
exit(EXIT_FAILURE);
}
while ((result = read(fd, &ch, 1)) > 0) {
/* Okunan byte işleniyor */
}
if (result < 0) {
perror("read");
exit(EXIT_FAILURE);
}
close(fd);
[Makale] Programların Komut Satırı Argümanları
İşletim sistemi tarafından prosese geçirilen komut satırı argümanları program içerisinden çeşitli biçimlerde elde edilebilmektedir. En yaygın yöntem komut satırı argümanlarının programın başlangıç fonksiyonunun parametrelerinden elde edilmesidir. Örneğin, C ve C++’ta komut satırı argümanları main fonksiyonuna parametre olarak geçirilirler. Bu dillerin standartlarına göre programın başlangıç noktasını (entry point) belirten main fonksiyonunun parametrik yapısı ve geri dönüş değeri aşağıdaki iki durumdan biri biçiminde olmalıdır:
int main(void) { /* ... */ }
int main(int argc, char *argv[]) { /* ... */ }
[Makale] UNIX/Linux Sistemlerinde Proseslerin Yaratılması ve Sonlandırılması
Hemen her işletim sistemi bir proses yaratıldığında, o prosese ilişkin bilgileri bir veri yapısında saklar. Proses bilgilerinin saklandığı bu veri yapısına proses kontrol bloğu (process control block) denilmektedir.[1] Örneğin UNIX türevi sistemlerde proseslerin gerçek (real) ve etkin (effective) kullanıcı ve grup id’leri, çalışma dizinleri (current working directories), açmış olduğu dosyalar gibi önemli bilgilerin hepsi, onların kontrol bloklarında tutulmaktadır. Proses kontrol bloğunun nasıl düzenlendiği ve tam olarak hangi elemanlara sahip olduğu sistemden sisteme, hatta aynı sistemlerde versiyondan versiyona değişebilmektedir. Örneğin Linux sistemlerinde proses kontrol bloğu oldukça fazla elemana sahip olan task_struct yapısı ile temsil edilmiştir. Bu yapının bir bölümünü aşağıda veriyoruz (Version:2.6.35, include/linux/sched.h):
[Makale] UNIX/Linux Sistemlerinde exec İşlemleri
UNIX/Linux sistemlerinde fork fonksiyonu prosesin yeni ve özdeş bir kopyasını oluşturmaktadır. Yani fork işlemi sonrasında alt ve üst prosesler aynı program kodunu (muhtemelen onların farklı kısımlarını) çalıştırıyor durumda olurlar. Halbuki pek çok uygulamada programcı yaratmış olduğu alt prosesin farklı bir program kodunu çalıştırmasını ister. İşte exec fonksiyonları prosesin başka bir program olarak çalışmaya devam etmesini sağlamaktadır. exec işlemleri sonrasında prosesin id değeri ve kontrol bloğu değişmez. Prosesin kod, data ve bss alanları çalıştırılabilen (executable) dosyadan alınarak yüklenir. Proses artık yaşamını başka bir program olarak sürdürür.
[Makale] UNIX Türevi Sistemlerde Blokeli ve Blokesiz Modda Dosya İşlemleri - Temel Bilgiler
Disk tabanlı dosyalar (regular file) üzerinde read ve write fonksiyonları ile okuma ve yazma yaparken uzun süreli bir bekleme söz konusu olmaz. Bu fonksiyonlar işlemlerini göreli olarak hızlı bir biçimde başarılı ya da başarısız olarak sonuçlandırırlar. Her ne kadar normal dosyalarla çalışırken işletim sistemi disk okuma ve yazmaları sırasında prosesi bloke ederek belli bir süre çizelge dışına çıkartabiliyorsa da buradaki bekleme önemli bir boyutta değildir. Halbuki bazı tür dosyalarla çalışırken bekleme belirsiz bir boyutta ve çok uzun süreli olabilmektedir
[Makale] Proseslerin Çevre Değişkenleri
Modern işletim sistemlerinde her prosesin bir çevre değişken bloğu vardır. Prosesin çevre değişken bloğu çevre değişkenlerinden ve onların değerlerinden oluşmaktadır. Örneğin, MESAJ bir çevre değişkeninin ismi olabilir, “Merhaba Dunya” ise onun değeri olabilir. Çevre değişkenleri pek çok işletim sisteminde proses yaratılırken belirlenebilmekte ya da üst prosesten (parent process) aktarılabilmektedir. Çevre değişkenlerinin üst prosesten aktarılması en çok karşılaşılan tipik durumdur.
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