6.1. #define
Ve #undef
Emirleri
#define
emri belirli
karakter dizileri için (makro
adı da verilen) takma isimler
tanımlamaya yarar. Sözdizimi şöyledir:
#define tanıtıcı_sözcük değiştirme_dizisi
Örneğin,
#define BLOKBASI { #define BLOKSONU } #define YORDAM static void
Tanımlanmakta olan tanıtıcı_sözcük’ün önünde ve arkasında
en az bir tane boşluk karakteri bulunmalıdır. Normal C tanıtıcı
sözcüklerinden ayırt etmek için, bu tür isimlerde büyük harflerin
kullanılması alışılagelmiştir. Bu isimlerin tanımı #undef
ile iptal edilmediği sürece, kaynak dosyanın geri kalan kısmında,
tanımında ondan sonra gelen karakter dizisi (yani değiştirme_dizisi)
ile değiştirilirler. Tanımlanmış bulunan bir tanıtıcı_sözcük için
ikinci bir #define
ancak değiştirme_dizisi aynı ise
kabul edilebilecektir.
Örneğin,
YORDAM hepsini_goster (…) BLOKBASI … BLOKSONU
program parçası, derlenmeden önce, önişlemci tarafından
static void hepsini_goster (…) { … }
şeklinde değiştirilecektir. Bir istisna: Eğer isim tırnak içinde yer alıyorsa, makro değişikliği yapılmayacaktır. Örneğin,
printf("BU YORDAM...");
deyimi değiştirilmeden, aynı şekilde kalacaktır.
Tipik olarak, #define
emri program için sayı, karakter dizisi
vs. değişmezleri tanımlamak için kullanılır, ancak değiştirme_dizisi,
daha önce veya sonra tanımlanan makrolar da dahil, her şeyi içerebilir.
Daha önce tanımlanmış bir makronun tanımını kaldırmak için
#undef
emrini, arkasına makro ismini belirterek,
kullanabilirsiniz. (Bu bölümün başındaki ilk örnekte Satır 13 ve
15’e bakınız.) Yani
#undef tanıtıcı_sözcük
Makrolara argüman da verilebilir. (Bölümün başında Satır 3 ve 11’e bakınız.) Genel şekil şöyledir:
#define tanıtıcı_sözcük(tanıtıcı_sözcükopt, …) değiştirme_dizisi
Makro ismi ile biçimsel argüman listesi
içindeki ilk
parametreden önce gelen sol parantez arasında herhangi bir boşluk
bulunmamalıdır. Bir fonksiyona benzemesine rağmen, bazı farklar vardır.
Makrolar satıriçi kod
oluştururlar, yani makronun kullanıldığı
her sefer, biçimsel argümanlar yerine gerçek argümanlar konularak, ilgili
değiştirme_dizisi onun yerini alır. Makro çağrısındaki argümanların
sayısı, bildirimde belirtilmiş bulunan biçimsel argümanların sayısı ile aynı
olmalı ve virgüllerle ayrılmalıdırlar. Tırnak işaretleri içinde veya bir çift
parantez arasında bulunan virgüller gerçek argüman ayırıcıları olarak
sayılmazlar.
Örneğin, Satır 11’de tanımlanmış makroya bir çağrı içeren
m = MAKS(x=10, c?y:z) + 5;
ifadesi önişlemci tarafından,
m = ((x=10)>(c?y:z) ? (x=10) : (c?y:z)) + 5;
şeklinde açılacaktır
. Şimdi makro tanımında
parametreler etrafında neden parantez kullanmış olduğumuzu görüyorsunuz. Hepsi
gereklidir. Aksi takdirde, istenen sonuç elde edilemeyecektir. Eğer
inanmıyorsanız, bir de parantezler olmadan deneyin. (İşleç önceliklerini
unutmayın!) Böyle durumlar için kural şöyledir:
- İlk olarak, değiştirme_dizisini sol parantezle başlatıp sağ
parantezle bitirin. Az önceki örnekte olduğu gibi, genelde, bir makro,
ifadenin bir bölümünü oluşturur. Bu aynı zamanda Satır 8’deki tanımda da
gerekli idi. [Neden?
durumunu inceleyin.]if (kar SON)
- İkinci olarak, değiştirme_dizisindeki bütün parametreleri parantez içine alın. Çünkü gerçek argümanların karmaşık ifadeler olabileceğini unutmayın.
Bir önceki örnekte olduğu gibi, dikkat ettiyseniz, makro
açılımından sonra bazı hesaplamalar birden fazla kez yapılabilir. Örneğin,
atama deyimi. Bu durum,
verimsiz olması dışında, bazı beklenmeyen sonuçların çıkmasına
da neden olabilir. Örneğin x=10
i
’nin
değerinin 6 olduğunu varsayın.
nin
değeri ne olacaktır? 6 mı? Bakalım. Önişlemci
MAKS(6,i++)
şeklinde açacaktır. Böylece değeri 7 olacaktır. Ayrıca,
((6)>(i++) ? (6) : (i++))
i
’nin yeni değeri 7 değil de 8 olacaktır.
Eğer değiştirme_dizisinde bir parametrenin önüne
konursa, makro açılımından sonra
çift tırnak içine alınacaktır, yani argüman bir karakter dizisine
dönüştürülecektir. Ayrıca böyle bir argümanın içinde bulunan
#
ve "
karakterlerinin önüne \
eklenecektir.\
Eğer değiştirme_dizisi içinde bir
simgesi varsa, bu işlecin önünde ve arkasında bulunan isimlerin
birbirine yapıştırılacağı şekilde, ##
ve etrafındaki her türlü beyaz boşluk karakteri çıkarılacaktır.
Örneğin##
#define cagir(x) yord ## x()
tanımını ele alalım. Bu makroyu
cagir(1);
şeklinde kullandığımızda
yord1();
şeklinde açılacaktır.
Daha yeni C standardında, değişken sayıda argüman alan makro tanımına izin
verilmiştir. Eğer makro tanımındaki parametrelerin sonunda üç nokta
(...
) varsa, makro çağrısında bunlara denk gelen argümanlar
__VA_ARGS__
isminde “bir parametre”ye atanırlar.
Makronun değiştirme_dizisi içinde bunu uygun bir yerde kullanabilirsiniz.
Örneğin,
#define bas(f,...) printf("bas: "f, __VA_ARGS__)
şeklinde tanımlanmış bas
makrosu şu şekilde
kullanılabilir:
bas("%d %s %f\n", 1, "iki", 3.0);