## ve __LINE__ ile C makrosu oluşturma (konumlandırma makrosu ile belirteç birleştirme)


107

Satır numarasına dayalı bir adla bir işlev oluşturan bir C makrosu oluşturmak istiyorum. Şöyle bir şey yapabileceğimi düşündüm (gerçek işlevin parantez içinde ifadeleri olurdu):

#define UNIQUE static void Unique_##__LINE__(void) {}

Şunun gibi bir şeye genişleyeceğini umuyordum:

static void Unique_23(void) {}

Bu işe yaramıyor. Belirteç birleştirme ile, konumlandırma makroları gerçek anlamda ele alınır ve şu şekilde genişler:

static void Unique___LINE__(void) {}

Bunu yapmak mümkün mü?

(Evet, ne kadar gereksiz görünürse görünsün bunu yapmak istememin gerçek bir nedeni var).



Yanıtlar:


176

Sorun, bir makro değişiminiz olduğunda, önişlemcinin makroları yalnızca dizgeleştirme operatörü #veya belirteç yapıştırma operatörü ##uygulanmadıysa yinelemeli olarak genişletmesidir . Bu nedenle, fazladan yönlendirme katmanları kullanmanız gerekir, belirteç yapıştırma operatörünü yinelemeli olarak genişletilmiş bir argümanla kullanabilirsiniz:

#define TOKENPASTE(x, y) x ## y
#define TOKENPASTE2(x, y) TOKENPASTE(x, y)
#define UNIQUE static void TOKENPASTE2(Unique_, __LINE__)(void) {}

Ardından, __LINE__genişletme sırasında satır numarasına genişletilir UNIQUE( #veya ile ilgili olmadığı için ##) ve ardından token yapıştırma işlemi TOKENPASTE,.

Aynı satırda makronun __COUNTER__birden fazla örneğine sahip olmanız gerektiğinde, her değerlendirildiğinde yeni bir tam sayıya genişleyen makro da vardır UNIQUE. Not: __COUNTER__MS Visual Studio, GCC (V4.3'ten beri) ve Clang tarafından desteklenir, ancak standart C değildir.


3
Korkarım bu GNU cpp ile çalışmıyor. TOKENPASTE kullanan LINE bir hazır olarak. TOKENPASTE (Unique_, LINE ) Unique___LINE__
DD olarak

3
@DD: D'oh, şimdi düzeltildi. 1'e değil, 2 katmana ihtiyacı var.
Adam Rosenfield

__COUNTER__Makro gcc benim için işe yaramadı; her ne kadar __LINE__biri ilan edildiği gibi çalıştı.
Tyler

2
Herkes çalıştıkları için ekstra bilgi Bit COUNTER göre msdn.microsoft.com/en-us/library/b0084kay(v=vs.80).aspx onu Microsoft'a bir makro özgüdür.
Elva

3
Neden 2 seviyeli yönlendirmeye ihtiyacınız olduğuna dair herhangi bir açıklama var mı? Bunu # ve ## eksiklerinden sadece biriyle denedim ve bu VS2017'de onu genişletmiyor. Görünüşe göre aynı şey GCC için de geçerli. Ancak 2. bir yönlendirme seviyesi eklerseniz, o zaman genişler. Sihir mi?
Gabe Halsmer

-2

GCC, sonucun "dizgeleştirilmesi" gerekmedikçe "sarmalama" (veya gerçekleştirme) gerektirmez. Gcc'nin özellikleri vardır, ancak TÜMÜ düz C sürüm 1 ile yapılabilir (ve bazıları Berkeley 4.3 C'nin çok daha hızlı olduğunu ve nasıl kullanılacağını öğrenmeye değer olduğunu savunur).

** Clang (llvm), makro genişletme için BEYAZ UZAYI DOĞRU YAPMAZ - boşluk ekler (bu, daha fazla ön işleme için C Tanımlayıcısı olma sonucunu kesinlikle yok eder) **, clang sadece # veya * makro genişletme yapmaz C Önişlemcisi olarak on yıllardır bekleniyor. En iyi örnek X11'i derliyor, makro "Concat3" bozuldu, bunun sonucu artık MISNAMED C Identifier'dır, ki bu tabii ki inşa edilemiyor. ve ben bir şeyler inşa etmeye başlıyorum başarısızlık onların mesleğidir.

Sanırım buradaki yanıt "standartları çiğneyen yeni C kötü C'dir", bu korsanlar her zaman (ad alanlarını bozar) herhangi bir neden olmaksızın varsayılanları değiştirmeyi seçerler, ancak gerçekten "C'yi iyileştirmezler" (kendi söyledikleri dışında: Diyelim ki, henüz kimsenin onları sorumlu tutmadığı tüm kırılmalardan neden sıyrıldıklarını açıklamak için bir mekanizma yapıldı).


Daha önceki C ön işlemcilerinin UNIq_ () __ 'i desteklememesi bir sorun değil çünkü kodda "derleyici marka korsanlığının bilgisayar korsanlığı olarak işaretlenmesine" izin veren ve aynı zamanda standartları etkilemeden işlevini yerine getiren # pragma'yı desteklediler: aynı varsayılanlar işe yaramaz wonton kırılmasıdır ve bir işlevin aynı adı kullanırken (ad alanı soygunu) yaptığı şeyi değiştirmek de bence kötü amaçlı yazılımdır

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.