2014-07-25 25 views
5

Bir üçüncü taraf kitaplığı Bir sorunun çözümünde çalışmaya çalışıyorum. Sorun kütüphane makro gömülü GCC en iç içe işlevlerini kullanır ve Clang iç içe işlevlerini desteklemez ve bunun için herhangi bir planı (Bkz, Clang Bug 6378 - error: illegal storage class on function) sahiptir. İşte Clang için iç içe işlevli GCC temizleme makrosunu yeniden yazınız.

beni ve Clang için ağrı noktası makro var: Burada

#define RAII_VAR(vartype, varname, initval, dtor) \ 
    /* Prototype needed due to http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36774 */ \ 
    auto void _dtor_ ## varname (vartype * v); \ 
    void _dtor_ ## varname (vartype * v) { dtor(*v); } \ 
    vartype varname __attribute__((cleanup(_dtor_ ## varname))) = (initval) 

Ve bu nasıl onun (kod yorumlardan) kullandı:

* void do_stuff(const char *name) 
* { 
*  RAII_VAR(struct mything *, thing, find_mything(name), ao2_cleanup); 
*  if (!thing) { 
*   return; 
*  } 
*  if (error) { 
*   return; 
*  } 
*  do_stuff_with_thing(thing); 
* } 

Clang User Manua l durumlarını C++ kullanmak ve taklit etmek için bir lambda işlevi. En iyi strateji olduğundan emin değilim ve bir C projesi olasılıkla değil bir C++ yama kabul edecek (bunlar katran olasılıkla olur ve beni ilk tüyü).

o Clang onun (1) daha uzlaşmacı, ve (2) orijinal fonksiyonu semantiğini korur, böylece makro yeniden yazmak için bir yolu var mı?

+0

başka fail GLIBC olup. Bkz: (http://sourceware.org/glibc/wiki/FAQ#Why_do_I_get:.60.23 [I alıyorum?, GNU CC ile GNU libc'yi derlemeye çalışırken '# hatası 'glibc optimizasyonu olmadan derlenmiş edilemez''] error_.22glibc_cannot_be_compiled_without_optimization.22.27.2C_when_trying_to_compile_GNU_libc_with_GNU_CC.3F) bu arada – jww

+2

, o Asterisk: sen clang kazanılmış varsa http://svn.asterisk.org/svn/asterisk/trunk/include/asterisk/utils.h derlemek RAII_VAR makrosu, bu katkıyı yukarı aktararak, büyük ölçüde takdir edilecektir. Bunun için birkaç açık konu var. –

+2

Tabii ki sizden biri bu konuyla ilgili yamaya katkıda bulunmadıysa: https://issues.asterisk.org/jira/browse/ASTERISK-20850 :-) –

cevap

6

Clang GCC iç içe işlevleri desteklemez, ama o bile C modunda, destek Objective C-style "blocks" yapar: (?)

void f(void * d) { 
    void (^g)(void *) = ^(void * d){ }; 
    g(d); 
} 
Ayrıca gcc ve clang komutu ile çağırmak yerine gerek

geçişte Derleyici için -fblocks -lBlocksRuntime.

Doğrudan bir blok olarak cleanup değeri kullanamazsınız, çünkü bir işlev adı olması gerekir, bu nedenle (here'dan fikirler çalmak) bir dolaylı katman eklemeniz gerekir. hükümsüz blokları temizlemek için tek bir fonksiyon tanımlanır, ve RAII'd değişken, kapsam sonunda çalıştırmak istediğiniz blok olun: bloklar kapanışları oluşturmak Çünkü

typedef void (^cleanup_block)(void); 
static inline void do_cleanup(cleanup_block * b) { (*b)(); } 

void do_stuff(const char *name) { 
    cleanup_block __attribute__((cleanup(do_cleanup))) __b = ^{ }; 
} 

, daha sonra yerleştirebilirsiniz blok ...

void do_stuff(const char *name) { 
    struct mything * thing; 
    cleanup_block __attribute__((cleanup(do_cleanup))) __b = ^{ ao2_cleanup(thing); }; 
} 

... ve bu, daha önce olduğu gibi kapsam sonunda çalışmalıdır blokta temizleme tarafından çağrılan doğrudan içindeki temizleme için değişkenler üzerinde işlemler. Makro yeniden düzenleme ve birden çok bildirimleri ile çalışır, böylece bir __LINE__ ekleyin: Böyle

#define CAT(A, B) CAT_(A, B) 
#define CAT_(A, B) A##B 

#define RAII_VAR(vartype, varname, initval, dtor) \ 
    vartype varname = (initval); \ 
    cleanup_block __attribute__((cleanup(do_cleanup))) CAT(__b_, __LINE__) = ^{ dtor(varname); }; 

void do_stuff(const char *name) { 
    RAII_VAR(struct mything *, thing, NULL, ao2_cleanup); 
    ... 

şey, neyse.