我以前用 c 写程序时不太注意指针类型转换需要注意的问题, 直到前段时间犯了一个类型转换的错误。
这是一个 websocket 服务端的程序。根据 websocket 协议,websocket 的消息帧荷载长度范围是 64bit 以下。于是我把接收函数的一个返回接收长度的指针参数类型声明为 uint64_t *msg_len
:
void ws_get_msg(const uint8_t *buf, const struct ws_frame_ctx *f_ctx,
uint8_t *msg, uint64_t *msg_len)
{
uint64_t i;
const uint8_t *payload = buf + f_ctx->payload_offset;
*msg_len = f_ctx->payload_len;
if (f_ctx->is_masked)
for (i = 0; i < f_ctx->payload_len; i++)
msg[i] = payload[i] ^ f_ctx->masking_key[i % 4];
else
memcpy(msg, payload, f_ctx->payload_len);
}
我这样调用上面这个函数:
ws_get_msg(buf->data, &frame_ctx,
conn->msg->data, (uint64_t *)&conn->msg->used);
conn->msg
的结构是这样的:
struct buf {
size_t max;
size_t used;
uint8_t *data;
};
结果程序运行的时候,一直解析不了正确的消息,调试发现调用ws_get_msg()
后conn->msg->data
这个指针变为 0 了。
原来我把这个指向size_t
类型(32位)的指针&conn->msg->used
作为参数传进ws_get_msg()
后,这句:
*msg_len = f_ctx->payload_len;
把紧挨着的*data
成员覆盖为 0 了。
在《Linux 内核设计与实现》(第3版)19.4.1节列举了一个因对齐引发的问题,也是与指针类型转换相关。