[英]Defining function macros
gcc 4.4.1 C99
我编写了一个函数,用于向用户显示消息。 这项工作正常,我将需要它具有可伸缩性,因为我将在以后添加更多错误代码。
但是,输入将是优先级,error_code和错误的简短描述。 我已经包含了功能和行号。
但是,我想将函数调用包装到宏中,但是不确定如何去做吗?
谁能指出我的写作方向?
非常感谢您的任何建议,
#include <stdio.h>
#include <stdarg.h>
typedef enum
{
ST_BIND_ERR = 1,
ST_SOCK_ERR,
ST_CONNECT_ERR,
ST_ACCEPT_ERR
}error_codes;
typedef enum
{
ST_CRITICAL = 1,
ST_WARNING,
ST_DEBUG,
ST_INFO
}priority;
#define REPORT(prio, err, msg) /* Defining macro here */
void report_msg(int prio, int err, const char *fmt, ...);
int main(void)
{
printf("=== Starting program ===\n");
report_msg(ST_WARNING, ST_CONNECT_ERR, "Error trying to make connection : FUNCTION [ %s ] : LINE [ %d ]",
__func__, __LINE__);
return 0;
}
void report_msg(int prio, int err, const char *fmt, ...)
{
va_list ap;
char priority_msg[512] = {0};
char error_code[256] = {0};
char format[256] = {0};
char output_msg[256] = {0};
switch(prio)
{
case ST_CRITICAL:
sprintf(priority_msg, "[ ST_CRITICAL ]");
break;
case ST_WARNING:
sprintf(priority_msg, "[ ST_WARNING ]");
break;
case ST_DEBUG:
sprintf(priority_msg, "[ ST_DEBUG ]");
break;
case ST_INFO:
sprintf(priority_msg, "[ ST_INFO ]");
break;
default:
sprintf(priority_msg, "[ UNKNOWN_PRIO ]");
break;
}
switch(err)
{
case ST_BIND_ERR:
sprintf(error_code, "[ ST_BIND_ERR ]");
break;
case ST_SOCK_ERR:
sprintf(error_code, "[ ST_SOCK_ERR ]");
break;
case ST_CONNECT_ERR:
sprintf(error_code, "[ ST_CONNECT_ERR ]");
break;
case ST_ACCEPT_ERR:
sprintf(error_code, "[ ST_ACCEPT_ERR ]");
break;
default:
sprintf(error_code, "[ UNKNOWN_ERR ]");
break;
}
va_start(ap, fmt);
vsprintf(format, fmt, ap);
va_end(ap);
sprintf(output_msg,"%s %s %s", priority_msg, error_code, format);
fprintf(stderr, output_msg);
}
C99支持vararg宏 ,您似乎可以使用它来使其更加方便:
#define REPORT(prio, err, format, ...) report_msg(prio, err, format, __VA_ARGS__)
不过,这似乎并没有比仅调用函数节省太多的工作。 也许您应该重新定义REPORT
宏以包含优先级,还是其他?
调用方实际上需要可变数量的参数吗? 例如,您是否希望他们能够做这样的事情?
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 ]
最后说明:如果这些优先级和错误代码仅与此功能一起使用,则最好首先将它们#define定义为字符串,然后将相应的参数更改为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则更易于阅读。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.