2013-04-24 26 views
5

Yapıma benzeyecek bir makro arıyordum. Bazı başka amaçlar için yararlı olabilir"Makroda" makro C

with (lock(&x), unlock(&x)) { 
    ... 
} 

: kullanım gibi bir şey olmalıdır.

bu makro ile geldi:

#define __with(_onenter, _onexit, v) \ 
    for (int __with_uniq##v=1; __with_uniq##v > 0;)\ 
     for (_onenter; __with_uniq##v > 0; _onexit) \ 
      while (__with_uniq##v-- > 0) 

#define _with(x, y, z) __with(x, y, z) 
#define with(_onenter, _onexit) _with(_onenter, _onexit, __COUNTER__) 

O gerektiğini, çünkü 3 iç içe döngüler vardır:

  • Muhtemelen değişken _onenter başlatmak (C99 elbette yalnızca)

    1. Başlatma döngü sayacı (örn. with (int fd=open(..), close(fd)))
    2. Kod bloğunun içine break izin verin.

    Ben XV6 OS için kod üzerinde kullandım ve oldukça kullanışlı görünüyor (continue çok izin verilir. Ve makro assert() bunu dışarı değiştirilebileceğini).

    Sorum şu: bu tür bir makroyla ilgili en büyük sorun nedir? Yani, sadece bir C makrosunun kullanımı (özellikle yeni kontrol akışı yapısı uygulayan).

    Şimdiye kadar bu dezavantajları/sorunlar olduğunu belirledik:

    1. return ya goto (örneğin fd < 0 gibi) hataları için
    2. desteği yok (ama çekirdek kodunda bazı goto s kaydedebilirsiniz) desteği yok. Bence bu tamir edilebilir.
    3. gnu89/c99 ve sadece üstü (döngü sayacı. Benzersiz değişken numarası gerekli değildir)
    4. Basit kilit açma işlevinden biraz daha az verimlidir. Bunun önemsiz olduğuna inanıyorum.

    Başka sorunlarınız var mı? C benzer yapıyı uygulamak için daha iyi bir yolu var mı?

  • cevap

    6

    Bu makro beni korkutuyor. traditional approach using gotos'u tercih ederim.

    Bu yaklaşım ilkeldir, ancak çoğu C programcısı desene aşinadır ve eğer değilse, yerel kodu okuyarak anlayabilirler. Gizli bir davranış yok. Sonuç olarak, oldukça güvenilir.

    Makronuz akıllıdır, ancak çoğu kişi için yeni olabilir ve gizli yakalamalarla birlikte gelir. Yeni katkıda bulunanlar "return veya goto ile bir blokta yok" gibi "break çevreleyen döngüden değil, bloğun dışına çıkacak" gibi düşünce kuralları olmalıdır. Korkarım sık rastlanılırdı.

    Bu yapının kötüye kullanılması için derleyiciye uyarı ekleyebilirseniz, denge değişecektir. With clang, bu bir seçenek gibi görünüyor. Bu durumda kötüye kullanım tespit edilir ve kodunuz diğer derleyiciler için taşınabilir kalır. Eğer GCC ve Clang kendinizi sınırlamak için istekli iseniz

    , sen cleanup özelliğini kullanabilirsiniz.Bu senin örnek şu şekilde görünmesi gerektiğini, yani kapsam dışına çıktığında

    lock_t x = NULL __attribute__((cleanup(unlock))); 
    lock(&x); 
    

    Ve unlock

    değişkene bir işaretçi ile çağrılır. Bu, return ve goto gibi diğer dil özellikleriyle ve hatta karışık C/C++ projelerindeki istisnalarla bile bütünleşir.

    +0

    Oh. Sonunda cevabı ... Ben cleanup' 'bilmiyordum, teşekkür ederim - yararlıdır geliyor. Makro onun scariness yanında daha spesifik sorunlar, var mı? – Elazar

    +1

    "İade" için destek eksikliği, işlevlerin ortasında "iade" ifadelerine karşı katı bir kodlama standardıyla çalışmadığınız sürece bir anlaşma kesicisi gibi görünüyor. Bir 'with' bloğunda bir' return' göze çarpmayan olmazdı ama çalışma anında hasara yol açıyor olacaktır. – pdw

    +0

    Anlıyorum ve return' büyük bir sorundur 'konusunda hemfikir (böylece' cleanup' çok daha iyidir). Ama aynı şekilde katı kodlama standardı gerektirmiyor mu? Bu açıdan goto'nun avantajları nelerdir? – Elazar