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
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:
- count the number of arguments
- expand differently depending on the number of arguments
- append to
__VA_ARGS__
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
FIRST(firstarg)
FIRST_HELPER(firstarg, throwaway)
firstarg
İki ya da daha fazla, aşağıdaki gibi genişler
FIRST(firstarg, secondarg, thirdarg)
FIRST_HELPER(firstarg, secondarg, thirdarg, throwaway)
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:
REST(firstarg)
REST_HELPER(NUM(firstarg), firstarg)
REST_HELPER2(SELECT_10TH(firstarg, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway), firstarg)
REST_HELPER2(ONE, firstarg)
REST_HELPER_ONE(firstarg)
- (boş)
İki veya daha fazla bağımsız değişken ile genişleme şöyle der:
REST(firstarg, secondarg, thirdarg)
REST_HELPER(NUM(firstarg, secondarg, thirdarg), firstarg, secondarg, thirdarg)
REST_HELPER2(SELECT_10TH(firstarg, secondarg, thirdarg, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway), firstarg, secondarg, thirdarg)
REST_HELPER2(TWOORMORE, firstarg, secondarg, thirdarg)
REST_HELPER_TWOORMORE(firstarg, secondarg, thirdarg)
, secondarg, thirdarg
Nasıl DockStyle kullanmak için.WPF sta...
Nasıl standart bir şekilde lider/sonda...
Hangi fonksiyonları C standart kütüpha...
Kullanarak standart Ad...
Nasıl bir web sitesi için standart olm...