Standart C Programlama Dili


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? if (kar SON) durumunu inceleyin.]
  • İ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, x=10 atama deyimi. Bu durum, verimsiz olması dışında, bazı beklenmeyen sonuçların çıkmasına da neden olabilir. Örneğin i’nin değerinin 6 olduğunu varsayın. MAKS(6,i++)nin değeri ne olacaktır? 6 mı? Bakalım. Önişlemci ((6)>(i++) ? (6) : (i++)) şeklinde açacaktır. Böylece değeri 7 olacaktır. Ayrıca, 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);