通过套接字发送整数同时避免违反严格的别名规则

Sending integer over socket while avoid breaking strict aliasing rule

我试图用 C 语言通过网络发送一个整数(更具体地说,uint32_t 字节)。根据 Stack Overflow 上的其他示例和答案,我相信我发送的数据是正确的;然而,当接收到字节时,我在不破坏 strict aliasing rule 的情况下遇到 casting/converting 到 uint32_t 的问题。这是我最初尝试的一个例子:

发件人:

uint32_t num = htonl(100);
char* converted_num = (char*)#
send(client_sock, converted_num, sizeof(num), 0);

接收者:

char buf[8192];
recv(socket, buf, 8192, 0);
uint32_t test = ntohl(*(uint32_t*)&buf);
printf("%d\n", (int)test);

虽然这看起来可行,但我收到反馈说行 uint32_t test = ntohl(*(uint32_t*)&buf); 违反了严格的别名规则。这是我修复严格别名违规的尝试:

char buf[8192];
recv(socket, buf, 8192, 0);
uint32_t test = ntohl(*(uint32_t*)memcpy(&(uint32_t){0}, &buf[0], sizeof(uint32_t)));
printf("%d\n", (int)test);

这会导致程序崩溃,即我的问题是在通过 c 套接字传输整数时如何最有效地避免违反严格的别名规则 (windows)。

把它分成几行:

uint32_t tmp;
memcpy(&tmp, buf + whatever, sizeof tmp);
result = ntohl(tmp);

你也可以把它变成一个内联函数:

static inline uint32_t get_u32(char *from) {
    uint32_t tmp;
    memcpy(&tmp, from, sizeof tmp);
    return ntohl(tmp);
}

...

uint32_t test = get_u32(buf + whatever);

您的原始代码在严格别名方面没有任何问题——无论是谁给您的反馈都是不正确的。 存在的问题是对齐——无法保证 char buff[8192]; 对除 char 以外的任何类型都正确对齐(尽管可能会)。您可以通过使用 malloc:

分配缓冲区来避免该问题
char *buf = malloc(8192);

malloc 将始终 return 适合分配给任何类型的内存。然后你的代码

recv(socket, buf, 8192, 0);
uint32_t test = ntohl(*(uint32_t*)buf);
printf("%d\n", (int)test);

是安全的,尽管您可能应该检查 malloc 是否成功。

而不是 char,使用 uint32_t 并放弃所有转换。使用正确的类型打印并使用 recv().

返回的正确类型
//char buf[8192];
uint32_t buf[8192/sizeof(uint32_t)];

//recv(socket, buf, 8192, 0);
ssize_t len = recv(socket, buf, sizeof buf, 0);

if (len != -1) { 
  if (len % sizeof *buf != 0) { ; } // TBD code to handle non-multiples of 32-bits
  len /= sizeof *buf;
  for (ssize_t i = 0; i< len; i++) {
    //uint32_t test = ntohl(*(uint32_t*)&buf);
    //printf("%d\n", (int)test);
    printf("%" PRIu32 "\n", buf[i]);
  }
}