1 Nisan 2021 Perşembe

Enum tür ve numaralandırma

 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...