Istnieje dobrze znany problem z pustymi argumentami dla makr wariadycznych w C99.
przykład:
#define FOO(...) printf(__VA_ARGS__)
#define BAR(fmt, ...) printf(fmt, __VA_ARGS__)
FOO("this works fine");
BAR("this breaks!");
Użycie BAR()
powyższego jest rzeczywiście nieprawidłowe zgodnie ze standardem C99, ponieważ rozszerzy się do:
printf("this breaks!",);
Zwróć uwagę na końcowy przecinek - nie działa.
Niektóre kompilatory (np. Visual Studio 2010) po cichu pozbędą się tego końcowego przecinka. Inne kompilatory (np .: GCC) obsługują wstawianie ##
przed __VA_ARGS__
, na przykład:
#define BAR(fmt, ...) printf(fmt, ##__VA_ARGS__)
Ale czy istnieje sposób zgodny ze standardami, aby uzyskać takie zachowanie? Może używasz wielu makr?
Obecnie ##
wersja wydaje się dość dobrze obsługiwana (przynajmniej na moich platformach), ale naprawdę wolałbym użyć rozwiązania zgodnego ze standardami.
Zapobiegawczy: wiem, że mógłbym po prostu napisać małą funkcję. Próbuję to zrobić za pomocą makr.
Edycja : Oto przykład (choć prosty), dlaczego chciałbym używać BAR ():
#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);
Spowoduje to automatyczne dodanie nowej linii do moich instrukcji logowania BAR (), przy założeniu, że fmt
jest to ciąg znaków C w podwójnym cudzysłowie. NIE drukuje nowej linii jako oddzielnej funkcji printf (), co jest korzystne, jeśli rejestrowanie jest buforowane wierszami i pochodzi z wielu źródeł asynchronicznie.
__VA_OPT__
słowie kluczowym. Zostało to już „przyjęte” przez C ++, więc spodziewam się, że C pójdzie w ich ślady. (nie wiem, czy to oznacza, że został przyspieszony do C ++ 17, czy też jest ustawiony na C ++ 20)
BAR
zamiastFOO
w pierwszej kolejności?