Нужно ли вызывающей стороне на самом деле переменное количество аргументов? Например, вы хотите, чтобы они могли делать что-то подобное?
REPORT(ST_WARNING, ST_CONNECT_ERR, "Error trying to make connection : "
"FUNCTION [ %s ] : LINE [ %d ], target address [ %s]", target);
Полагаю, что так, потому что если нет, то вообще не нужно varargs.
Итак, исходя из этого предположения, я думаю, что сначала сделаю это:
#define REPORT(prio, error, format, ...) report_msg(prio, error, format, __func__, __LINE__, __VA_ARGS__)
Но , если вы это сделаете, то вы полагаетесь на вызывающего, чтобы правильно включить функцию и строку в сообщение об ошибке. Это хлопот для звонящего. Так что на самом деле я мог бы пойти на что-то вроде этого:
#define REPORT(prio, error, format, ...) report_msg(prio, error, format, __func__, __LINE__, __VA_ARGS__)
void report_msg(int prio, int err, const char *fmt, const char *func, int line, ...) {
// print the prio and error codes
// ...
// I've put some fprintf in here to avoid introducing even more buffers,
// but you can still do what you were doing before, building one big message.
fprintf("in function %s at line %d\n", func, line);
va_start(ap, fmt);
vsprintf(format, fmt, ap);
va_end(ap);
fprintf("\t%s\n", format);
}
Тогда вызывающая сторона делает это:
REPORT(ST_WARNING, ST_CONNECT_ERROR, "target address [ %s ]", my_addr);
И ошибка выглядит так:
[ST_WARNING] [ST_CONNECT_ERROR] in function main at line 28
target address [ 69.59.196.211 ]
Последнее замечание: если эти коды приоритетов и ошибок используются только с этой функцией, то, возможно, лучше сначала определить их как строки, и изменить соответствующие параметры на const char*
. Таким образом, вам не нужен оператор switch, и вы можете легко добавлять новые коды (или вызывающие могут просто быстро указать какую-то другую строку, если они хотят привлечь внимание при выполнении отладки).
Даже если они должны быть числами, ваши переключатели содержат ненужное форматирование. Вы могли бы сделать что-то вроде этого:
char *priority_msg;
switch(prio) {
case ST_WARNING: priority_msg = "[ ST_WARNING ]"; break;
// other cases...
default: priority_msg = "[ UNKNOWN_PRIO ]"; break;
}
или это:
char *priorities[] = {"[ UNKOWN_PRIO ]", "[ ST_ERROR ]", "[ ST_WARNING ]", ... };
char *priority_msg = priorities[0];
if (prio >= 0) && (prio < sizeof(priorities) / sizeof(*priorities)) {
priority_msg = priorities[prio];
}
Это работает, если вы знаете, что приоритеты являются последовательными числами, начиная с 1, и до тех пор, пока вы убедитесь, что перечисление и строки синхронизированы. Так что это немного сложнее изменить, чем большой оператор switch, но IMO немного легче читать.