[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 özgü bilgileri bir veri yapısında saklar. Çalışmakta olan proseslere ilişkin bilgilerin saklandığı veri yapısına proses kontrol bloğu denilmektedir.[1] UNIX türevi sistemlerde prosesin gerçek ve etkin (effective), kullanıcı ve grup id’leri, prosesin çalışma dizini, açmış olduğu dosyalar gibi prosese özgü önemli bilgilerin hepsi proses kontrol bloğunda 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 ve Windows Sistemlerinde Stdin, Stdout ve Stderr Dosyaları
Yalnızca UNIX/Linux sistemlerinde değil modern işletim sistemlerinin çoğunda aygıtlar birer dosyaymış gibi ele alınmaktadır. Örneğin klavye ve ekran -aslında birer dosya olmadığı halde- işletim sistemi tarafından sanki birer dosyaymış gibi işleme sokulurlar. Aygıtlara ilişkin bu tür dosyalar için de birer dosya betimleyicisi ve dosya nesnesi vardır. Bu betimleyicilerle işlem yapıldığında işletim sisteminin dosya alt sistemi aslında bu dosyaların birer aygıta ilişkin olduğunu anlar ve okuma/yazma amacıyla o aygıtlara yönelir. UNIX türevi sistemlerdeki çokbiçimliliği (polymophism) andıran bu tasarıma Sanal Dosya Sistemi (Virtual File System) denilmektedir.
[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] 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.
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;
foreach döngü değişkeninin read-only olmasının basit bir nedeni var. foreach deyimi çokbiçimli olarak IEnumerable arayüzü yoluyla dolaşım uygular.[1] IEnumerable arayüzünün GetEnumerator metodu IEnumerator arayüzü türündendir. IEnumerator arayüzünün elemana erişmekte kullanılan Current property’si de read-only’dir. Aşağıdaki foreach döngüsüne bakın:
foreach (V v in x)
<deyim>
C# standartlarına göre (burada bazı ayrıntıları göz ardı edeceğim) bu deyimin eşdeğeri şöyledir:[2]
{
IEnumerator e = x.GetEnumerator();
E e = x.GetEnumerator();
try
{
V v;
while (e.MoveNext())
{
v = (V) e.Current;
<deyim>
}
}
finally
{
// e.Dispose(); --> E, IDisposable arayüzünü destekliyorsa
}
}
Gördüğünüz gibi bu tanımlamaya göre foreach döngü değişkeni read-write olamaz. Ancak bu noktada IEnumerable.Current property’sinin neden read-only olduğu da sorulabilir. Eğer Current property’si read-only olmasaydı bu arayüzü destekleyen collection sınıfların read-only olma olanakları kaldırılmış olurdu. Tabi yine de C++’taki gibi const iterator sistemi uygulanabilirdi. Örneğin kütüphaneye IEnumerable arayüzünün yanı sıra bir de IConstEnumerable arayüzü eklenebilirdi. Microsoft tasarımcıları böyle bir tasarımın sadeliği bozacağını düşünmüş olmalılar.
Burada C# için söylediklerim VB.NET için de aynı nedenlerden dolayı geçerli. Java'daki foreach deyimi de C#'takine çok benziyor..NET'teki IEnumerable arayüzünün Java'daki karşılığı Iterable arayüzü. Ancak Java’da döngü değişkeni read-only değil. Fakat döngü değişkeni yerel bir değişken gibi ele alındığından ona atama yapılması collection nesnesinin ilgili elemanına atama yapıldığı anlamına da gelmiyor. Peki C/C++'ta durum nedir? Bildiğiniz gibi C ve C++’ta zaten foreach deyimi yok. Ancak bu döngünün “Range Based Loop” ismiyle C++’a eklenmesine çoktan karar verildi. C++0x’te belirtilen bu döngü işlevsel olarak C# ve Java’dakinden farklı. Burada döngü değişkeni referans olabildiği için diziler üzerinde güncelleme işlemi de yapılabiliyor.
[1] Generic konusunun C#’a eklenmesiyle IEnumerable arayüzünün yanı sıra IEnumerable<T> arayüzü de foreach ile ilişkilendirilmiştir. Burada ben ayrıntıya girmek istemedim.
[2] C# standartlarına göre bir collection sınıfın foreach ile kullanılması için IEnumerable ya da IEnumerable<T> arayüzünü desteklemesi zorunlu değildir. Eğer collection sınıf GetEnumerator metodunu doğrudan bulunduruyorsa yine foreach deyimi ile kullanılabilir. Yine ben bu ayrıntılara girmek istemedim.
CSD C ve Sistem Programcıları Derneği