2010-12-28 29 views
9

Nesneleri bir makro tanımına eklemek için standart C'de veya GNU uzantılarında herhangi bir yol var mı? E.g., ben ekleyebilirsiniz
#define List foo bar
olarak tanımlanan bir makro verilen bas o List bunu
#define List foo bar bas tanımlanmış sanki genişler böylece?Bir önişlemci makrosuna ekleyebilir miyim?

Ben böyle bir şey yapabileceğini umuyordum:

#define List foo bar bas 

#define List_ Expand(List) 
#undef List 
#define List Expand(List_) quux 

ama Expand() makro tanımlamak anlamaya olamaz bu yüzden istediğimi yapacağım.

Motivasyon: Ben ayrımcılığa oynuyorum /bu satırlar boyunca sendikaları tagged:

struct quux_foo { int x; }; 
struct quux_bar { char *s; }; 
struct quux_bas { void *p; }; 

enum quux_type {quux_foo, quux_bar, quux_bas}; 

struct quux { 
    enum quux_type type; 
    union { 
     struct quux_foo foo; 
     struct quux_bar bar; 
     struct quux_bas bas; 
    } t; 
}; 

Bu X-makro için iyi bir yerdir anlamaya. quux_* yapıları senkronize edilmemiş olsun, Tabii

#define X(t) quux_ ## t, 
enum quux_type {quux_table}; 
#undef X 

#define X(t) struct quux_ ## t t; 
struct quux { 
    enum quux_type type; 
    union {quux_table} t; 
}; 
#undef X 

, bu yüzden istiyorum: Bir makro
#define quux_table X(foo) X(bar) X(bas)
numaralandırma & yapı asla Bu şekilde tanımlanan ve edilebilmektedir tanımlarsanız senkronizasyonu bozuluyor sadece yasal olarak böyle bir şey yapmak:

struct quux_foo { int x; }; 
#define quux_table quux_table X(foo) 

struct quux_bar { char *s; }; 
#define quux_table quux_table X(bar) 

struct quux_bas { void *p; }; 
#define quux_table quux_table X(bas) 

(Eh, gerçekten yapabilmek istiyorum neyi
gibi bir şeymember_struct(quux, foo) { int x; };
ama iyi (yeniden) makro olamaz farkında makrolar içinden tanımlanmış değilim.)

neyse, bu benim motive örnek. Bunu başarmanın bir yolu var mı?

Yükseltme X-makro tekniğinin bu kitaplık ile nasıl çalışacağını bana gösterebilirseniz, işlem öncesi örnekler iyidir.

+0

Evet, bu kesinlikle yapılabilir, eğer redefinition konusunda ısrar etmiyorsanız. Ham preprocessor kullanırsanız biraz acı. Boost.Preprocessor ile biraz daha az acı verici. Ne yazık ki benim soğuğum, bir yöntem üretecek kadar dürüst düşünmemi engelliyor. Umarım bir başkası olur. – swestrup

cevap

5

Etkin olarak, hayır.

Makrolar tembel olarak değerlendirilir. Ne zaman #define List_ Expand(List), onun yedek listesi, Expand, (, List ve ) dört belirteçleri dizisidir. Makroyu bir yedek listeye genişletmenin herhangi bir yolu yoktur.

Makro çağrıldığında, tüm makro değiştirme gerçekleşir.

Otomatik kod oluşturma için Boost.Preprocessor kütüphanesini kullanmayı tavsiye ederim. Bu biraz iş, ancak bunu kullanarak bazı fairly impressive things yapabilirsiniz. C.

+0

Açıklama için teşekkürler. –

2

Bunun yardımcı olup olmadığından emin değilim, ancak değişken arg makroları yapabilirsiniz. X264 projesinden Bay Conrad, önişlemci istismarını çok seviyor. Yardımcı olabileceği gibi ses çıkarırsanız, daha fazla bilgi edinebilirsiniz Here

+1

C99 variadic makroları güzel (ve onları kullandım), ama bu benim sorum ile gerçekten alakalı değil. (Doğrudan değil, en azından gerçek çözümün _use_ variadic makroları bir yerde bulabileceğini düşünebilirim.) –

2

ile tamamen uyumlu olmalıdır. Bir yolu var!Eğer kendi tanımı içinde bir makro pop Eğer bu gcc elde edilebilir yeni _Pragma anahtar kelime (msvc ile değil gerçi)

kullanma

makro ilk kez genişletilir kadar genişleme var geciktirir. Bu, kendi tanımının önceki genişleme bölümünü yapmanıza olanak tanır. o öyle genişleme sırasında attı olduğundan Ancak, sadece bir kez kullanılabilir İşte

bazı örnek kod olsa, bu seçenek otomatik kod oluşturma adil biraz kolaylaştırması gerekir eylem

#define pushfoo _Pragma("push_macro(\"foo\")") //for convenience 
#define popfoo _Pragma("pop_macro(\"foo\")") 

#define foo 1 

pushfoo       //push the old value 
#undef foo      //so you don't get a warning on the next line 
#define foo popfoo foo , 2  //append to the previous value of foo 

pushfoo 
#undef foo 
#define foo popfoo foo , 3 

pushfoo 
#undef foo 
#define foo popfoo foo , 4 


foo //this whole list will expand to something like popfoo foo popfoo foo popfoo foo , 4 
    //which will in turn expand to 1 , 2 , 3 , 4 

foo //the second time this will expand to just 1 

bunu görmektir ne yazık ki sadece gcc'de (belki de clang, test edilmedi)

Dürüst olmak gerekirse, bunun neden çalışması gerektiğini anlayabilmem için bir neden yoktur, bu muhtemelen işe yaramayan tanımlanmamış davranışlardır. Bunun sebebi, foo'yu patlattıktan sonra, genişletilen geçerli makronun artık foo sembolünün genişlemesine izin veren foo adıyla ilişkilendirilmemesidir, ancak bu sadece benim varsayımım olan

İlgili konular