使用的是C++11
。
现在有三个宏:
#define CLIENT_INFO_FMT " from session#%u on %s:%d"
#define CLIENT_INFO_ARGS conn->session_id, port->host, port->port
#define CLIENT_INFO CLIENT_INFO_FMT, CLIENT_INFO_ARGS
其中,conn
、port
、port
都是结构体变量。
然后,有一个函数会去使用CLIENT_INFO
这个宏,如下:
swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "Bad Request: unknown protocol" CLIENT_INFO);
直接使用CLIENT_INFO
宏展开会有问题,但是如果分别使用CLIENT_INFO_FMT
和CLIENT_INFO_ARGS
的话,就没有问题,即:
swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "Bad Request: unknown protocol" CLIENT_INFO_FMT, CLIENT_INFO_ARGS);
如果我把宏CLIENT_INFO
修改为:
#define CLIENT_INFO " from session#%u on %s:%d", conn->session_id, port->host, port->port
然后使用CLIENT_INFO
宏,即:
swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "Bad Request: unknown protocol" CLIENT_INFO);
也会展开失败。所以这里的问题就是,为什么要分开使用CLIENT_INFO_FMT
和CLIENT_INFO_ARGS
才行?
调用关系如下:
swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "Bad Request: unknown protocol" CLIENT_INFO);
#define swoole_error_log(level, __errno, str, ...) \
do{ \
SwooleG.error = __errno; \
if (level >= SwooleG.log_level){ \
size_t _sw_error_len = sw_snprintf(sw_error, SW_ERROR_MSG_SIZE, "%s (ERRNO %d): " str,__func__,__errno,##__VA_ARGS__); \
SwooleG.write_log(level, sw_error, _sw_error_len); \
} \
} while(0)
size_t sw_snprintf(char *buf, size_t size, const char *format, ...)
{
va_list args;
va_start(args, format);
int retval = vsnprintf(buf, size, format, args);
va_end(args);
vsnprintf
会出现段错误。因为format
字符串是正确的,所以我判断是va_list
出了问题。
简化你的问题,得到以下示例:
输出: