Как преобразовать переменную функцию аргумента в макрос? - PullRequest
3 голосов
/ 25 августа 2009

У меня есть функция переменного аргумента, которая печатает сообщения об ошибках в моем приложении, код которого приведен ниже:

void error(char *format,...)
{   va_list args;
    printf("Error: ");
    va_start(args, format);
    vfprintf(stderr, format, args);
    va_end(args);
    printf("\n");
    abort(); 
}

Эта функция используется в следующих случаях:

error("invalid image width %d and image height %d in GIF file %s",wid,hei,name);

Функция error() вызывается из разных мест с разными аргументами (функция переменного аргумента).

Функциональный подход работает отлично.

Теперь, если мне нужно преобразовать эту функцию в макрос, как мне это сделать? Я пытался сделать это как:

#define error(format)  {va_list args;\
    printf("Error: ");\
    va_start(args, format);\
    vfprintf(stderr, format, args);\
    va_end(args);\
    printf("\n"); abort()}

Но это не выводит аргументы правильно.

Что не так в определении макроса выше?

Что за исправление?

Ответы [ 5 ]

2 голосов
/ 25 августа 2009

Если ваш компилятор поддерживает переменные макросы в стиле ISO, вы можете определить макрос следующим образом:

#define error(...) \    
    fprintf(stderr, "Error: ");   \
    fprintf(stderr, __VA_ARGS__); \
    fprintf(stderr, "\n"); \
    abort();

В качестве альтернативы, если вы используете GCC, есть также макрос Variadic стиля GNU, используемый как таковой:

#define error(format, args...) \    
    fprintf(stderr, "Error: ");   \
    fprintf(stderr, format , ## args); \
    fprintf(stderr, "\n"); \
    abort();

Для получения дополнительной информации см. http://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html

Обновление

Если ваш компилятор не поддерживает переменную макрокоманду, альтернативой (плохой?) Будет придерживаться подхода va_list в функции. Если вы хотите, чтобы определение находилось в заголовочном файле, возможно, статическая встроенная функция?

static inline void error(const char *fmt, ...) {
#define PRINT_ERROR
    va_list args;
    fprintf(stderr, "Error: "); 
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    fprintf(stderr, "\n");
    abort();
#endif
}
1 голос
/ 25 августа 2009

Вот статья с некоторыми примерами переменных аргументов, используемых в макросе . Похоже, он должен делать то, что вы ищете. Вы можете использовать __VA_ARGS__ в своем макросе.

Какой компилятор вы используете?

0 голосов
/ 25 августа 2009

Есть общее расширение, которое делает то, что вы хотите, просто напишите:

#define error(args...) (fputs("Error: ",stdout),printf(args),puts(""))

Пользователи C99 также могут сказать:

#define error(...) (fputs("Error: ",stdout),printf(__VA_ARGS__),puts(""))

но есть некоторые проблемы с использованием __VA_ARGS__. К счастью, есть расширение GCC, но вы вернулись к использованию расширения, специфичного для компилятора, и режим args... стал более доступным.

0 голосов
/ 25 августа 2009

Многие компиляторы поддерживают переменные макросы в стиле GNU, например:

#define error(format,args...) do { \
  fprintf(stderr, "error: " format "\n", ##args); \
  abort(); \
} while(0)

Однако, если вы стремитесь к переносимости, не используйте переменные макросы.

0 голосов
/ 25 августа 2009

Макросы (пока?) Не поддерживают переменные аргументы и, в любом случае, использование va_list здесь не сработает, оно работает только с переменными function arguments.

Почему вы хотите заменить функцию (которая, по вашему мнению, отлично работает) на макрос?

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