请教一个宏替换的问题?

使用的是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

其中,connportport都是结构体变量。

然后,有一个函数会去使用CLIENT_INFO这个宏,如下:

swoole_error_log(SW_LOG_TRACE, SW_ERROR_HTTP_INVALID_PROTOCOL, "Bad Request: unknown protocol" CLIENT_INFO);

直接使用CLIENT_INFO宏展开会有问题,但是如果分别使用CLIENT_INFO_FMTCLIENT_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_FMTCLIENT_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出了问题。

阅读 2.2k
1 个回答

简化你的问题,得到以下示例:

#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

struct w {
    unsigned session_id;
    char host[10];
    int port;
};

int main()
{
    w* conn = new w{ 0,"localhost",8080 };
    w* port = conn;
    char SW_LOG_TRACE[2000];
    snprintf(SW_LOG_TRACE,
        sizeof SW_LOG_TRACE,
        "Bad Request: unknown protocol" CLIENT_INFO);
    puts(SW_LOG_TRACE);
}

输出:

Bad Request: unknown protocol from session#0 on localhost:8080
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题