SORU
7 NİSAN 2011, PERŞEMBE


Standart alternatif'in GCC #__#__ hile?VA_BESTEN

C99'da variadic macros için boş argümanlar ilewell-known problem bir yoktur.

örnek:

#define FOO(...)       printf(__VA_ARGS__)
#define BAR(fmt, ...)  printf(fmt, __VA_ARGS__)

FOO("this works fine");
BAR("this breaks!");

BAR() yukarıda kullanımını genişletmek olacaktır, çünkü gerçekten C99 standardına göre yanlıştır,:

printf("this breaks!",);

Sondaki uygulanabilir virgül not.

(Örn: Visual Studio 2010) Derleyiciler bazı sessizce kurtulmak için virgül sondaki alacak. Diğer Derleyiciler (örnek: GCC) gibi __VA_ARGS__ destek ön ## koyarak:

#define BAR(fmt, ...)  printf(fmt, ##__VA_ARGS__)

Ama orada standartlarla uyumlu bir şekilde bu davranış elde etmek için mi? Kullanarak birden fazla makro olabilir mi?

Şu anda, ## sürüm desteği (en azından benim platformlarında) gibi oldukça ama oldukça standartlarla uyumlu bir çözüm kullanmak istiyorum.

Önleyici: sadece küçük bir fonksiyon yazabilirim biliyorum. Bu makroları kullanarak yapmaya çalışıyorum.

Edit: İşte bir örnek (basit de olsa) BAR kullanmak isterim neden():

#define BAR(fmt, ...)  printf(fmt "\n", ##__VA_ARGS__)

BAR("here is a log message");
BAR("here is a log message with a param: %d", 42);

Bu otomatik olarak benim BAR için bir yeni satır ekler() günlük ifadeler fmt her zaman çift tırnaklı C-string. bir varsayarak Eğer günlük satır tamponlu ve birden fazla kaynaktan uyumsuz geliyorsa avantajlıdır. ayrı bir printf olarak yeni satır baskı YOK(),

CEVAP
23 HAZİRAN 2012, CUMARTESİ


Bir argüman kullanabileceğiniz hile sayım var.

Burada standart uyumlu jwd soru BAR() ikinci örnek uygulamak için bir yol:

#include <stdio.h>

#define BAR(...) printf(FIRST(__VA_ARGS__) "\n" REST(__VA_ARGS__))

/* expands to the first argument */
#define FIRST(...) FIRST_HELPER(__VA_ARGS__, throwaway)
#define FIRST_HELPER(first, ...) first

/*
 * if there's only one argument, expands to nothing.  if there is more
 * than one argument, expands to a comma followed by everything but
 * the first argument.  only supports up to 9 arguments but can be
 * trivially expanded.
 */
#define REST(...) REST_HELPER(NUM(__VA_ARGS__), __VA_ARGS__)
#define REST_HELPER(qty, ...) REST_HELPER2(qty, __VA_ARGS__)
#define REST_HELPER2(qty, ...) REST_HELPER_##qty(__VA_ARGS__)
#define REST_HELPER_ONE(first)
#define REST_HELPER_TWOORMORE(first, ...) , __VA_ARGS__
#define NUM(...) \
    SELECT_10TH(__VA_ARGS__, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE,\
                TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway)
#define SELECT_10TH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, ...) a10

int
main(int argc, char *argv[])
{
    BAR("first test");
    BAR("second test: %s", "a string");
    return 0;
}

Bu aynı kandırmak için kullanılır:

Açıklama

Bu strateji ilk tartışma __VA_ARGS__ ve geri kalan (varsa) ayırmaktır. Bu da, ilk tartışmadan sonra bir şeyler eklemek mümkün ama daha önce (varsa) yapar.

FIRST()

Bu makro sadece ilk argüman için, geri kalan atarak genişletir.

Uygulaması basittir. throwaway bağımsız FIRST_HELPER() ... en az bir ihtiyacı olduğu için gerekli olan iki bağımsız değişken alır sağlar. Bir argüman ile, aşağıdaki gibi genişler

  1. FIRST(firstarg)
  2. FIRST_HELPER(firstarg, throwaway)
  3. firstarg

İki ya da daha fazla, aşağıdaki gibi genişler

  1. FIRST(firstarg, secondarg, thirdarg)
  2. FIRST_HELPER(firstarg, secondarg, thirdarg, throwaway)
  3. firstarg

REST()

Bu makro her şeyi ama ilk argüman (eğer birden fazla bağımsız değişken varsa ilk tartışmadan sonra virgül de dahil olmak üzere) için genişler.

Bu makro uygulanması çok daha karmaşıktır. Genel strateji sayısını saymak için argümanlar (bir veya birden fazla) ve sonra genişletmek için ya REST_HELPER_ONE() (varsa yalnızca bir bağımsız değişken verilen) veya REST_HELPER_TWOORMORE() (eğer iki veya daha fazla bağımsız değişken verilen). REST_HELPER_ONE() kalan argümanlar boş küme yani ilk sonra tartışmalar var yok sadece bir şey için genişler. REST_HELPER_TWOORMORE() ayrıca basit bir virgül her şeyi izledi ilk bağımsız değişken dışında genişler.

Bağımsız NUM() makro kullanarak sayılır. Bu makro genişletir ONE eğer tek bir değişken olduğunu düşünürsek TWOORMORE eğer iki ila dokuz argümanlar göz önüne alındığında, ve sonları ise 10 ya da daha çok değer verilir (çünkü genişler için 10 değişken).

NUM() makro SELECT_10TH() makro bağımsız değişkenleri belirlemek için kullanır. Adından da anlaşılacağı gibi, 38* *sadece 10 argüman için genişler. Üç nokta en az 11 bağımsız geçirilmesi gerekiyor (standart üç nokta için en az bir argüman olması gerektiğini söylüyor). Bu yüzden NUM() geçer throwaway en son bağımsız değişken (onsuz geçen bir tartışma NUM() neden olacaktır sadece 10 ayetleri böyle geçti SELECT_10TH(), hangisi ihlal standart).

REST_HELPER_ONE() REST_HELPER_TWOORMORE() ya da seçimi REST_HELPER2() 47 *genişleme REST_HELPER_ birleştirerek yapılır. REST_HELPER() amacı NUM(__VA_ARGS__) tam REST_HELPER_ ile birleştirilmiş önce genişletilmiş olduğundan emin olmak için olduğunu unutmayın.

Genişleme ile bir argüman şöyle der:

  1. REST(firstarg)
  2. REST_HELPER(NUM(firstarg), firstarg)
  3. REST_HELPER2(SELECT_10TH(firstarg, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway), firstarg)
  4. REST_HELPER2(ONE, firstarg)
  5. REST_HELPER_ONE(firstarg)
  6. (boş)

İki veya daha fazla bağımsız değişken ile genişleme şöyle der:

  1. REST(firstarg, secondarg, thirdarg)
  2. REST_HELPER(NUM(firstarg, secondarg, thirdarg), firstarg, secondarg, thirdarg)
  3. REST_HELPER2(SELECT_10TH(firstarg, secondarg, thirdarg, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway), firstarg, secondarg, thirdarg)
  4. REST_HELPER2(TWOORMORE, firstarg, secondarg, thirdarg)
  5. REST_HELPER_TWOORMORE(firstarg, secondarg, thirdarg)
  6. , secondarg, thirdarg

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

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • cdgotx

    cdgotx

    8 Kasım 2011
  • Submissions101

    Submissions1

    23 ŞUBAT 2007
  • The Verge

    The Verge

    8 AĞUSTOS 2006