SORU
26 Kasım 2008, ÇARŞAMBA


C ön işlemci ise bir döngü yazmak

Bakış eğitim/hack noktası, (gerçekten böyle kod istemem) bu soruyu soruyorum.

C ön işlemci direktifleri kullanarak sadece döngü uygulamak mümkün. Makrolar yinelemeli olarak, bu nasıl gerçekleştirilebilir? genişletildi anlıyorum

Teşekkürler

CEVAP
10 Mayıs 2012, PERŞEMBE


Bir süre döngü uygulamak istiyorsanız, bu kadar basit özyineleme kullanmak gerekir. Özyineleme yapmak için en kolay yolu ertelenmiş bir ifade kullanmaktır. Ertelenmiş bir ifade daha tarar tamamen genişletmek için gerektiren bir ifadesidir:

#define EMPTY()
#define DEFER(id) id EMPTY()
#define OBSTRUCT(id) id DEFER(EMPTY)()
#define EXPAND(...) __VA_ARGS__

#define A() 123
A() // Expands to 123
DEFER(A)() // Expands to A () because it requires one more scan to fully expand
EXPAND(DEFER(A)()) // Expands to 123, because the EXPAND macro forces another scan

Neden bu kadar önemli? İyi bir makro taranmış ve genişliyor, devre dışı bırakılması, bir bağlam oluşturur. Bu devre dışı bırakılması kapsamında şu anda genişleyen makro için bir belirteç, mavi boyalı neden olur. Böylece, boyalı mavi bir makro artık genişleyecektir. Bu makrolar yinelemeli olarak genişletin. Ancak, devre dışı bırakılması, bir bağlam yalnızca bir tarama sırasında, yani mavi boyalı olma bizim makrolar önleyebiliriz bir genişleme ertelendiğinde var. Sadece ifade etmek için daha fazla tarama uygulamak için ihtiyacımız olacak. O EVAL bu makro kullanarak yapabiliriz:

#define EVAL(...)  EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
#define EVAL5(...) __VA_ARGS__

Sonra, biraz mantık, vb gibi) için bazı operatörler tanımlayın:

#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__

#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)

#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
#define NOT_0 ~, 1,

#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0

#define BOOL(x) COMPL(NOT(x))

#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t

#define IF(c) IIF(BOOL(c))

Şimdi tüm bu makrolar WHILE özyinelemeli bir makro yazabiliriz. Kendisi için geri yinelemeli olarak bakın WHILE_INDIRECT makro kullanıyoruz. Bu farklı bir tarama(ve devre dışı bırakılması farklı bir bağlamda kullanarak) genişleyecektir beri mavi boyalı, olmaktan makro engeller. WHILE makro yüklem bir makro, operatör bir makro ve bir devlet variadic bağımsız olan) alır. Yüklem makro false 0) dönünceye kadar makro bu operatör durumuna uygulayarak tutar.

#define WHILE(pred, op, ...) \
    IF(pred(__VA_ARGS__)) \
    ( \
        DEFER(WHILE_INDIRECT) () \
        ( \
            pred, op, op(__VA_ARGS__) \
        ), \
        __VA_ARGS__ \
    )
#define WHILE_INDIRECT() WHILE

Gösteri amaçlı, sadece bağımsız değişken sayısı 1 olduğunda denetleyen bir dayanak oluşturmak için

#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)

#define IS_1(x) CHECK(PRIMITIVE_CAT(IS_1_, x))
#define IS_1_1 ~, 1,

#define PRED(x, ...) COMPL(IS_1(NARGS(__VA_ARGS__)))

Önümüzdeki iki belirteçleri herhangi bir parametre hangi bir operatör, yaratıyoruz. Biz de son çıktıyı işleyecek son bir operatör (M olarak da adlandırılır) oluşturmak:

#define OP(x, y, ...) CAT(x, y), __VA_ARGS__ 
#define M(...) CAT(__VA_ARGS__)

Sonra WHILE makro kullanarak:

M(EVAL(WHILE(PRED, OP, x, y, z))) //Expands to xyz

Tabii ki, yüklem veya operatör her türlü geçebilir.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Alexander Johnson

    Alexander Jo

    26 Temmuz 2008
  • MotoManTV

    MotoManTV

    10 Aralık 2009
  • The Weavers of Eternity Paracord Tutorials

    The Weavers

    1 Ocak 2014