Yazılan birçok programda, yalnızca belirli anlamlı değerler alabilen değişkenler kullanma
gereksinimi duyulur. Örneğin bir "Boolean" değişkeni, yalnızca iki değere sahip olabilir: "Doğru" ve "Yanlış". Haftanın bir gününü tutacak bir değişken, haftanın yedi günü olduğuna göre yedi farklı değerden birini alabilir. Başka bir örnek olarak bir oyun kağıdının rengini tutacak bir değişkeni verilebilir. Böyle bir değişken yalnızca 4 değişik değer alabilir: Sinek, Karo, Kupa, Maça. Böyle değişkenler tamsayı türlerinden tanımlanabilir: int renk; renk = 1; Yukarıdaki örnekte renk isimli değişken bir oyun kağıdının renk bilgisini tutuyor. Bu değişkene 1 değerinin atanması renk değerinin Karo olduğunu gösteriyor. Böyle bir teknik uygulamalarda pekala kullanılabilir. Ancak bu tekniğin bazı sakıncaları vardır. 1. Kodu okuyan renk isimli değişkene yapılan atamalarda kullanılan tamsayı değişmezlerinin neyi temsil ettiği konusunda doğrudan bilgi alamaz. Kodun okunabilirliği azalır. Örneğin renk = 1; şeklinde bir atama doğrudan renk değişkenine "karo" değerinin verilmiş olduğu biçiminde de anlamlandıramaz. 2. Derleyici renk değişkeni ile ek bir kontrol yapamaz. Derleyici renk değişkeninin yalnızca 4 farklı değerden birini alması gerektiğinin farkında değildir. Derleyiciye böyle bir bilgi verilmemiştir. Örneğin böyle bir değişkene 10 gibi bir değerin atanması anlamsızdır. Ancak derleyici derleme sırasında bu yanlışlığı bulamaz, bir hata ya da bir uyarı iletisiyle veremez. C dili, isimlendirilmiş belirli tamsayı değerlerini alabilen, bir tür yaratılmasına olanak veren bir araca sahiptir. Bu araca numaralandrırma (enumaration) ve bu araçla ilişkili kullanılan değişmezlere (enumaration constants) "numaralandırma değişmezleri" denir. Bir numaralandırma türünün ve bir numaralandırma türüne ilişkin değişmezlerin bildirimi aşağıdaki gibi yapılır: enum [enum türünün isimi] {değişmez1,değişmez2, ......}; enum bir anahtar sözcüktür. Derleyici küme ayraçları arasında isimlendirilmiş değişmezleri 0 değerinden başlayarak artan tamsayı değerleriyle eşler. Örnek : enum Renk {Sinek, Karo, Kupa, Maca}; Yukarıdaki bildirimle Sinek değişmezi 0, Karo değişmezi 1, Kupa değişmezi 2, Maca değişmezi ise 3 değerini alır. enum Bool {TRUE, FALSE}; burada TRUE değişmezi 0 FALSE değişmezi ise 1 değerini alır. enum Months {January, February, March, April, May, June, July, August, September, Oktober, November, December}; Bu bildirim ile numaralandırma değişmezlerine January = 0, February = 1, ... December = 11 biçiminde artan değerler verilir. Numaralandırma değişmezlerine atama işleci ile küme ayraçları içinde değerler verilebilir, bu biçimde değer verilmiş bir numaralandırma değişmezinden sonraki değişmezin değeri önceki değerden bir fazlasıdır. enum Months {January = 1, February, March, April, May, June, July, August,September, Oktober, November, December}; Bu bildirim ile numaralandırma değişmezlerine January = 1, February = 2, ... December = 12 biçiminde artan değerler verilmiş olur. enum değişmezlerine int türü sayı sınırları içinde pozitif ya da negatif değerler verilebilir: enum RTVals { RT1 = -127, RT2, RT3, RT4 = 12, RT5, RT6, RT7 = 0, RT8, RT9 = 90 }; Yukarıdaki bildirim ile numaralandırma değişmezlerinin alacağı değerler aşağıdaki gibi olur: RT1 = -127, RT2 = -126, RT3 = -125, RT4 = 12, RT5 = 13, RT6 = 14, RT7 = 0, RT8 = 1, RT9 = 90 Bir numaralandırma bildiriminde kullanılan farklı numaralandırma değişmezlerinin değeri aynı olabilir. Aşağıdaki bildirim geçerlidir: enum Bool {YANLIS, FALSE = 0, DOGRU, TRUE = 1}; Bir numaralandırma değişmezinin ismi, aynı bilinirlik alanında kullanılan tüm isimlerden farklı olmalıdır. Bir numaralndırma değişmezi ismi ile aynı bilinirlik alanında bildirilen bir değişkenin isminin ya da bir başka numaralandırma değişmezinin isminin aynı olması geçersizdir. Numaralandırma isimleri (enum tag), yapı ve birlik isimleri gibi bilinirlik alanı kurallarına uyar. Bu isimler aynı bilinirlik alanındaki diğer numaralandırma, yapı ve birlik isimlerinden farklı olmalıdır. Bildirimlerde numaralandırma ismi (enumeration tag) hiç belirtilmeyebilir. Bu durumda genellikle küme ayracının kapanmasından sonra o numaralandırma türünden nesne(ler) tanımlanarak deyim sonlandırıcı atom ile bitirilir. enum {Sunday = 1, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}day1, day2, day3; Yukarıdaki örnekte day1, day2, day3 bildirimi yapılmış numaralandırma türünden (belirli bir tür ismi seçilmemiştir) yaratılmış değişkenlerdir. Böyle bir bildirim + tanımlama işleminin dezavantajı, artık bir daha aynı numaralandırma türünden başka bir değişkenin yaratılmamasıdır. Bildirilen bir numaralandırma türünden nesne tanımlamak da zorunlu değildir: enum {LOW = 10, HIGH = 20}; Yukarıdaki bildirim geçerlidir. Bildirilen türün bir ismi yoktur ama bu bildirimin görülür olduğu her yerde LOW ve HIGH numaralandırma değişmezleri kullanılabilir. Numaralandırma Türlerinin sizeof Değerleri Bir numaralandırma türünden tanımlanmış bir nesne için derleyici, kullanılan sistemde int türünün uzunluğu kadar bir yer ayırır. Derleyici için numaralandırma türünden bir nesne ile int türden bir nesne arasında fiziksel olarak herhangi bir fark bulunmaz. örneğin Unix altında : sizeof(enum Days) == sizeod(int) == 4 ifadesi doğrudur. Tabi bu kuralın bir kötü tarafı int türünün 2 byte olduğu bir sistemde kullanılabilecek en büyük numaralandırma değişmezinin değeri 32767 olabilir. Numaralandırmalar ve typedef Bildirimi Bir numaralandırma türü için de bir typedef bildirimi yapılabilir. Böylece türün kullanımında artık enum anahtar sözcüğünün kullanılmasına gerek kalmaz: typedef enum tagRenk{SINEK, KARO, KUPA, MACA} Renk; Bildiriminden sonra artık enum anahtar sözcüğü kullanılmadan Renk kart1, kart2, kart3, kart4; gibi bir tanımlama yapılabilir. typedef bildiriminden sonra artık Renk bir tür ismi belirtir. Şimdi de aşağıdaki örneğe bakalım: typedef enum {FALSE, TRUE} Bool; Artık Bool ismi FALSE ve TRUE değerlerini alabilen bir türün ismidir. [C++ dilinde yapı, birlik ve numaralandırma türlerine ilişkin isimler (tag) aynı zamanda türün genel ismi olarak kullanılabileceği için yukarıdaki gibi bir typedef bildirimine gerek yoktur.] Numaralandırma Türlerinin Kullanımı enum bildirimi ile yeni bir tür yaratıldığına göre, bu türden nesne ya da gösterici tanımlanabilir. Tanımlanacak işlevlerin geri dönüş değerleri ve/veya parametre değişkenleri de böyle bir türden olabilir: typedef enum {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}Days; typedef struct {int d, m, y}Date; Bir yapı türünün bildiriminde, elemanlar bir numaralandırma türünden seçilebilir: typedef struct { Days day; Months month; int year; }Date; Yukarıdaki örnekte Date isimli yapı türünün day ve month isimli elemanları Days ve Months isimli numaralandırma türlerindendir. Numaralandırma Değişmezleri Değişmez İfadesi Olarak Kullanılabilir Bir numaralandırma değişmezi bir değişmez ifadesi (constant expression) oluşturur. Bu yüzden numaralandırma değişmezleri değişmez ifadesi gereken yerlerde kullanılabilir. Aşağıdaki kodu inceleyin: enum {MIN_SIZE = 100, AVERAGE_SIZE = 500, MAX_SIZE = 1000}; void func() { int a[MIN_SIZE]; int b[AVERAGE_SIZE]; int c[MAX_SIZE]; /***/ } Yukarıdaki main işlevinin içinde tanımlanan a, b ve c isimlerinin boyutları numalandırma değişmezleri ile belirlenmiştir. Numaralandırma değişmezlerin switch deyiminin case ifadeleri olarak kullanılmaları çok sık karşılaşılan bir durumdur: Renk renk; /***/ switch (renk) { case SINEK: /***/ case KARO : /***/ case KUPA : /***/ case MACA : /***/ } Numaralandırma Türleri ile #define Değişmezlerinin Karşılaştırılması #define önişlemci komutu önişlemci programa ilişkindir. Fakat numaralandırma değişmezleri derleme aşamasında ele alınır. Bir #define simgesel değişmezi için bilinirlik alanı diye bir kavram söz konusu değildir, çünkü bilinirlik alanı derleyicinin anlamlandırdığı bir kavramdır. Ancak numaralandırma türleri ve değişmezleri için bilinirlik alanı kuralları geçerlidir. Eğer bir numaralandırma türü, bir işlev içinde bildirilmişse bu türe ilişkin numaralandırma değişmezleri söz konusu işlevin dışında bilinmez. Birden fazla #define simgesel değişmezi, mantıksal bir ilişki içinde kullanılsa bile, derleyici bu ilişkinin farkında olmaz. Bu yüzden, derleyici programın, bu simgesel değişmezlerin yanlış kullanımına ilişkin bir uyarı iletisi üretme şansına sahip olmaz. Ancak derleyici aynı tür kapsamında bildirilen numaralandırma değişmezlerinin arasındaki mantıksal ilişkinin farkındadır. Bunların yanlış kullanılması durumunda uyarı iletisi üretebilir. Numaralandırma değişmezleri de #define komutuyla tanımlanmış simgesel değişmezler gibi, nesne belirtmez. Örneğin : enum METAL {Demir, Bakir, Kalay, Cinko, Kursun}; /***/ Kalay = 3; /* Geçersiz */ Numaralandırma değişmezleri, mantıksal ilişki içinde bulunan belirli sayıda tanımlamalar için tercih edilir. Mantıksal ilişki içindeki bazı isimlerin bir tür kapsamı altında ele alınması okunabilirliği artırır. Örneğin: enum Gun {Pazartesi, Sali, Carsamba, Persembe, Cuma, Cumartesi, Pazar}; Derleyicilerin sistemlere yönelik sağladığı başlık dosyalarında, birçok numaralandırma türü ve bu türlere ilişkin numaralandırma değişmezleri tanımlanır. Örneğin aşağıdaki numaralandırma bildirimi 80x86 sistemlerinde çalışan bir Borland derleyicisinin graphics.h isimli başlık dosyasından alınmıştır: enum COLORS { BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY, DARKGRAY, LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE }; Numaralandırma Türlerine İlişkin Tür Dönüşümleri C dilinde bir numaralandırma türü derleyici tarafından fiziksel olarak int türü biçiminde ele alınır. Numaralandırma türleri ile diğer doğal türler arasında otomatik tür dönüşümü söz konusudur. Örneğin bir numaralandırma değişkenine int tüden bir değer atanabilir. Ya da int türden bir değişkene bir numaralandırma değişmezi atanabilir: typedef enum {OFF, HOLD, STANDBY, ON}Position; void func() { Position pos = 2; /* Geçerli */ int x = ON; /* Geçerli */ /***/ } Ancak numaralandırma değişkenlerine diğer doğal türlerden atama yapıldığında tür dönüştürme işlecinin kullanılması programın okunabilirliğini artırır: pos = (Position)2; Numaralandırma Değişmezlerinin Ekrana Yazdırılması Bir numaralandırma değeri ekrana standart printf işleviyle %d format karakteriyle eşlenerek yazdırılabilir. Numaralandırma değişmezinin tamsayı değerini değil de ismini ekrana yazdırmanın doğrudan bir yolu yoktur. Bu amaçla bir işlev yazılabilir
Hiç yorum yok:
Yorum Gönder
Her yorum bilgidir. Araştırmaya devam...