макроопределение - PullRequest
       5

макроопределение

3 голосов
/ 17 октября 2011

Я попытался определить макрос, как показано ниже.Вызов 1 не имеет проблем, но вызов 2 вызвал ошибку компилятора, поскольку третий аргумент недоступен.Как определить макрос, который поддерживает вызов 1 и вызов 2?

#define RDF_LOG(dbglevel, fmt, ...) (rdfDBG(dbglevel, " " fmt, __VA_ARGS__))
void rdfDBG(int dbglevel, const char *fmt, ...) { /* printf debug message */ }

RDF_LOG(kERROR, "Fail to open file %s\n", pinfile); /* Call 1 */
RDF_LOG(kERROR, "Insufficient Memory\n"); /* call 2 , compiler -> error: expected expression before ')' token */

Ответы [ 2 ]

4 голосов
/ 17 октября 2011

Вы получаете дополнительную запятую во втором раскрытии макроса, потому что у вас есть безусловная запятая после fmt в определении макроса.

Удаление параметра fmt из определения макроса, похоже, исправляетэта проблема;строка формата затем становится частью __VA_ARGS__:

#define RDF_LOG(dbglevel, ...) (rdfDBG(dbglevel, " " __VA_ARGS__))
void rdfDBG(int dbglevel, const char *fmt, ...) { /* printf debug message */ }

RDF_LOG(kERROR, "Fail to open file %s\n", pinfile); /* Call 1 */
RDF_LOG(kERROR, "Insufficient Memory\n");

Это расширяется до:

void rdfDBG(int dbglevel, const char *fmt, ...) { }

(rdfDBG(kERROR, " " "Fail to open file %s\n", pinfile));
(rdfDBG(kERROR, " " "Insufficient Memory\n"));

Кстати, похоже, что " " предназначено для того, чтобы формат былстроковый литерал (и моя измененная версия сохраняет это).Вы уверены, что хотите это сделать?Хотя это редко, полезно иметь не-литеральную строку формата.

2 голосов
/ 17 октября 2011

GCC Extensions

GCC имеет расширение для обработки этого (обратите внимание на пропущенную запятую перед ...):

Неправильно (ссылки __VA_ARGS__, что не разрешено в расширении GCC):

#define RDF_LOG(dbglevel, fmt ...) (rdfDBG(dbglevel, " " fmt, __VA_ARGS__))

Правильно (без ссылки __VA_ARGS__):

#define RDF_LOG(dbglevel, fmt...) (rdfDBG(dbglevel, " " fmt))
void rdfDBG(int dbglevel, const char *fmt, ...) { /* printf debug message */ }
enum { kERROR };

void x(const char *pinfile);
void x(const char *pinfile)
{
    RDF_LOG(kERROR, "Fail to open file %s\n", pinfile);
    RDF_LOG(kERROR, "Insufficient Memory\n");
}

Вы можете сказать, что я не использую расширение GCC - потому что я использую некоторые компиляторы, которые не являются GCC.

Существует также второй (специфичный для GCC) механизм, упомянутый Адамом в его комментарии:

#define RDF_LOG(dbglevel, fmt, ...) (rdfDBG(dbglevel, " " fmt, ## __VA_ARGS__))
void rdfDBG(int dbglevel, const char *fmt, ...) { /* printf debug message */ }
enum { kERROR };

void x(const char *pinfile);
void x(const char *pinfile)
{
    RDF_LOG(kERROR, "Fail to open file %s\n", pinfile);
    RDF_LOG(kERROR, "Insufficient Memory\n");
}

Стандарт C99

В противном случае вы должны использовать стандартный механизм C99:

#define RDF_LOG(dbglevel, ...) (rdfDBG(dbglevel, " " __VA_ARGS__))
void rdfDBG(int dbglevel, const char *fmt, ...) { /* printf debug message */ }

RDF_LOG(kERROR, "Fail to open file %s\n", pinfile); /* Call 1 */
RDF_LOG(kERROR, "Insufficient Memory\n");

Это в основном обманывает или обходит проблему для этого контекста. В общем случае C99 требует запятую и хотя бы один аргумент.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...