> C Dilindeki Tamponlu IO Sistemleri ("Buffered IO in C") : C'nin prototipleri içerisinde bulunan dosya fonksiyonları sistem fonksiyonlarının daha az çağrılmasına sağlamk içim tıpkı yukarıdaki örnekte yaptığımız gibi bir cache sistemi oluşturmaktadır. Standart C fonksiyonlarının oluşturduğu bu cache sistemine genellikle "cache" yerine "buffer" denilmektedir. Bu nedenle C'nin standart dosya fonksiyonlarına "tamponlu IO fonksiyonları (buffered IO functions)" da denilmektedir. Biz örneğin fgetc fonksiyonu ile dosyadan bir byte bile okumak istesek aslında fgetc bir grup byte'ı tek bir sistem fonksiyonu ile okuyup bize okunan tampondan byte'ı verir. Böylece diğer fgetc çağırmaları için yeniden sistem fonksiyonu çağrılmamakta doğrudan bilgiler bu tampondan alınmaktadır. Bu nedenle bir dosyadan bu biçimde byte byte okumalar için standart C fonksiyonları tercih edilmelidir. Aşağıda bu konuya ilişkin bir örnek verilmiştir: * Örnek 1, Şimdi yukarıda örneği standart C fonksiyonlarıyla deneyelim. Okumayı şöyle yapacağız: while ((ch = fgetc()) != EOF) { /* ... */ } Burada programın bu versiyonu aynı koşullar altında 0.025 saniye zaman almıştır. Üç deneyin aldığı zamanları yeniden anımsatmak istiyoruz Her defasında, -> read çağrılması (test1.c): 3.040 -> read fonksiyonu ile blok blok okuma yapılması (test2.c): 0.014 -> C'nin tamponlu fgetc fonksiyonu il byte byte okuma yapıması (test3.c): 0.025 Programın kodları ise şu şekildedir: /* test3.c */ #include #include #include void proc(int ch) { /* EMPTY */ } int main(int argc, char *argv[]) { FILE *f; int ch; double telapsed; clock_t start, stop; if (argc != 2) { fprintf(stderr, "wrong number of arguments!..\n"); exit(EXIT_FAILURE); } start = clock(); if ((f = fopen(argv[1], "rb")) == NULL) { fprintf(stderr, "cannot open file!...\n"); exit(EXIT_FAILURE); } while ((ch = fgetc(f)) != EOF) proc(ch); if (ferror(f)) { fprintf(stderr, "IO error!..\n"); exit(EXIT_FAILURE); } fclose(f); stop = clock(); telapsed = (double) (stop - start) / CLOCKS_PER_SEC; printf("%.3f\n", telapsed); return 0; } * Örnek 2, Bir dosyayı fgetc fonksiyonuyla byte byte okumak isteyelim. Bu fonksiyon tamponlu (yani cache sistemi ile) çalıştığına göre etkin bir kullanıma yol açacaktır. Pekiyi yukarıdaki örnekteki zamanların aşağıdaki gibi olmasının anlamı nedir? Her defasında, -> read çağrılması (test1.c): 3.040 -> read fonksiyonu ile blok blok okuma yapılması (test2.c): 0.014 -> C'nin tamponlu fgetc fonksiyonu il byte byte okuma yapıması (test3.c): 0.025 Neden fgetc fonksiyonun kullanıldığı versiyon bloklo read okumalarının yapıldığı versiyondan daha yavaş çalışmıtır? İki yöntemde de tampon 8192 byte uzunluğundadır. Programın fgetc versiyonunda her byte için fgetc fonksiyonu çaağrılmıştır. Bir fonksiyon çağırmanın da mikro düzeyde bir zmana kaybı vardır. Ayrıca fgetc fonksiyonu tampondan bilgiyi almak için de biraz zaman kaybı oluşturmaktadır. Bu nedenle standart C kütüphanesinde fgetc fonksiyonunun yanı sıra getc isimli benzer bir fonksiyon da bulundurulmuştur. Bu iki fonksiyon arasındaki tek fark getc fonksiyonunun bir makro olarak yazılmasına izin verilmesidir. Eğer getc fonksiyonu bir makro olarak yazılmışsa fonksiyon çağırmanın oluşturduğu göreli zaman kaybı (function call overhead) elimine edilmiş olacaktır. Ancak getc fonksiyonun bir makro biçiminde yazılması zorunlu tutulmamıştır. Yukarıdaki örnekte fgetc yerine getc fonksiyonun çağrılması gcc derleyicilerinde bir zaman kazancı sağlamamaktadır.