在 Windows x64 上,将局部变量的地址传递给 ZMQ_FD 的 zmq_getsockopt 始终会导致 EINVAL。下面的代码是重现问题的最小代码。
#include <zmq.h>
#include <stdio.h>
void zmq_perror(const char*);
int main(void)
{
const char *endpoint = "tcp://127.0.0.1:7100";
void *ctx = zmq_ctx_new();
if (ctx == NULL) { zmq_perror("zmq_ctx_new"); }
void *socket = zmq_socket(ctx, ZMQ_DEALER);
if (socket == NULL) { zmq_perror("zmq_socket"); }
int rc;
rc = zmq_connect(socket, endpoint);
if ( rc == -1 ) { zmq_perror("zmq_connect"); }
/*** This results in EINVAL ***/
int fd;
size_t fd_size = sizeof (fd);
rc = zmq_getsockopt(socket, ZMQ_FD, &fd, &fd_size);
if (rc == -1) { zmq_perror("zmq_getsockopt"); }
/*** This works without issue ***/
/*
int *fd = malloc(sizeof(int));
size_t fd_size = sizeof (fd);
rc = zmq_getsockopt(socket, ZMQ_FD, fd, &fd_size);
if (rc == -1) { zmq_perror("zmq_getsockopt"); }
*/
}
void zmq_perror(const char *f)
{
fprintf(stderr, "%s: %s\n", f, zmq_strerror(zmq_errno()));
abort();
}
使用第一个(联机帮助页)表单运行上述内容总是会产生:
zmq_getsockopt: Invalid argument
然而,第二个,使用 malloc 注释掉的表单没有问题。这对我来说是零意义,因为将局部变量的地址传递给 zmq_getsockopt 是完全合法的。
此问题仅在 Windows 上出现 64 位二进制文件;Windows 上的 32 位二进制文件或 linux 上的 64 位二进制文件没有问题。
这似乎也只是 ZMQ_FD 套接字选项的问题。ZMQ_TYPE 和 ZMQ_SNDHWM 工作没有问题。
Windows x64 上是否有一些我不知道的与 ZMQ_FD 相关的奇怪行为?
更新
所以我只是注意到我的“工作”代码实际上是错误的。
sizeof(fd)
以第二种形式获取指针的大小。实际上,它与 malloc 无关,因为一旦我将其更改为 sizeof(int) 应该是我再次得到 EINVAL:
/* Fail */
int *fd = malloc(sizeof(int));
size_t fd_size = sizeof(int);
rc = zmq_getsockopt(socket, ZMQ_FD, fd, &fd_size);
if (rc == -1) { zmq_perror("zmq_getsockopt"); }
事实证明,我显然需要在 windows x64 上使用带有 ZMQ_FD 的 64 位整数类型
/* Success! */
uint64_t fd;
size_t fd_size = sizeof(uint64_t);
rc = zmq_getsockopt(socket, ZMQ_FD, &fd, &fd_size);
if (rc == -1) { zmq_perror("zmq_getsockopt"); }
这非常令人困惑,因为 zmq_getsockopt 的 api 是int。这是一个错误吗?窗户怪癖?我很浓?
相关附录:
zmq 版本:3.2.3
编译器:使用 mingw-w64、rubenvb-4.8.0 为 64 位和 32 位二进制文件构建交叉编译
操作系统:Windows 7