从字节数组中解包整数

Unpacking integer from byte array

如果这很明显,请原谅我,但我正在使用字节数组通过网络发送数据,我需要向其中填充一个整数,然后在另一端将其取回。

示例中的类型定义:

uint8_t *dest;
uint8_t *ciphertext;
size_t  cbytes; // length of ciphertext
uint8_t iv[16];
uint8_t tag[16];

作者相关部分:

size_t bytes = 0;
memcpy(&dest[bytes], iv, sizeof(iv));
bytes = sizeof(iv);
memcpy(&dest[bytes], (void*)htonl(cbytes), sizeof(uint32_t));
bytes += sizeof(uint32_t);
memcpy(&dest[bytes], ciphertext, cbytes);
bytes += cbytes;
memcpy(&dest[bytes], tag, sizeof(tag));
bytes += sizeof(tag);

这是将 cbytes 作为整数填充到字节数组中的正确方法吗?如果不是,有什么更好的方法?

现在,有了这个字节数组,我如何将 cbytes 读回整数(或 size_t)?它的其余部分可以复制回来,但不确定如何处理整数。

你问的是这段代码:

memcpy(&dest[bytes], (void*)htonl(cbytes), sizeof(uint32_t));

不,这根本不正确。您正在将 htonl 的 return 值转换为指针。然而,它不是一个有效的指针。您 有一个 uint32_t 类型的对象用于发送:

uint32_t cbytes32 = htonl(cbytes);
memcpy(&dest[bytes], &cbytes32, sizeof(uint32_t));

在现代 C 中,也可以在一行中执行此操作,使用 复合文字 创建一个 uint32_t 内联数组:

memcpy(&dest[bytes], (uint32_t[]){ htonl(cbytes) }, sizeof(uint32_t));

但语法确实没有更好看。

要读入它,您需要将它读入类型为 uint32_t 的对象,然后 ntohl 它,以及可以存储到 [=20= 中的 return 值]:

uint32_t size32;
size_t size;
memcpy(&size32, src, sizeof size32)
size = ntohl(size32);

然后,如果您在其他地方可能使用 64 位 size_t 但在此处将其截断为 32 位,我会格外小心。可能没问题,但这需要记录在案。 64位对大家来说应该够用了,可惜没有htonll功能


最后,为了减少按键次数,您可以写 dest + bytes 而不是 &dest[bytes]。甚至更少,你可以再做一个指针:

uint8_t *cur = dest;
memcpy(cur, iv, sizeof iv);
cur += sizeof iv;
uint32_t cbytes32 = htonl(cbytes);
memcpy(cur, &cbytes32, sizeof cbytes32);
cur += sizeof cbytes32;
memcpy(cur, ciphertext, cbytes32);
cur += cbytes32;
memcpy(cur, tag, sizeof tag);
cur += sizeof tag;
size_t nbytes = cur - dest;

请注意,如果您使用的是 流式套接字 (TCP),通常无需将它们复制到中间缓冲区中 - 只需使用单独的 read 调用 - 或者至少,在调用 size 之后,不要费心将 long 数组复制到同一个缓冲区中。