坦率地说,这样的代码是否有效(除了缺少必要的错误检查,为简单起见,这里省略了)?
通过互联网发送数据的代码:
uint16_t i = htons(500);
sendto(sockfd, &i, sizeof(uint16_t), 0, &dest_addr, sizeof(struct sockaddr_in));
接收此数据的代码:
uint16_t i;
recvfrom(sockfd, &i, sizeof(uint16_t), 0, src_addr, sizeof(struct sockaddr_in));
i = ntohs(i);
if(i < 100 || i > 1000)
fprintf(stderr, "Received invalid data over the network\n");
else
do_something(i);
我担心的是,既然我读过C标准允许除unsigned char
之外的任何类型的陷阱值,那么我是否有可能通过网络获得这样的陷阱值,因此我'我写i = ntohs(i)
时会有UB吗?
或者POSIX是否保证uint16_t
和uint32_t
不会有陷阱值?
或者它不受任何官方标准的保证,但是绝大多数实现没有uint16_t
和uint32_t
的陷阱值,因此根据这个事实上的标准,我不这样做不得不害怕这个?
答案 0 :(得分:2)
C99指定固定宽度类型必须是二进制补码并且没有填充位。讨论陷阱表示的标准位表示在整数类型中,只有填充位可以导致陷阱表示。因此,我们甚至不需要深入了解POSIX以确保您的代码正常。
POSIX另外使得所有整数类型都是二进制补码(我现在无法找到它,要么是明确说明,要么是POSIX中某些其他东西的结果,我不记得)。
答案 1 :(得分:1)
我认为答案是&#34;是&#34;。你正在做的事情很好。
我认为你担心的是:
某些对象表示不需要表示对象类型的值。如果存储 对象的值具有这样的表示,并由左值表达式读取 没有字符类型,行为是未定义的。
对于uinxx_t,我不相信有任何陷阱值。比特值的所有组合产生有效数字(即对象表示)。即,所有位组合&#34;表示对象类型的值&#34;,因此您不能将uintxx_t初始化为陷阱值/表示。
标准接着说,我之前从未读过,所以这很有趣:
对于有符号整数类型...如果符号位为1,则该值应为 通过以下方式之一进行修改:
- 对应的值 符号位0被否定(符号和幅度);
- 符号位有 值 - (2N)(二进制补码);
- 符号位的值为 - (2N - 1) (一个补充)。
其中哪些适用于实现定义, as是否为符号位1的值和所有值位为零(for 前两个),或符号位和所有值位1(对于一个 补码),是陷阱表示或正常值。
因此,如果您使用已签名的整数,则可能会出现问题,但它似乎不适用于 un 已签名的整数。
答案 2 :(得分:1)
uint16_t
在内存中不能有陷阱值 - 有16个值位,没有填充位。但是,未初始化的局部变量(其地址从未被采用)将具有不确定的值。由于i
的地址在此处,它必须驻留在内存中,即使recvfrom
失败,它也会有一个有效的未指定值。
答案 3 :(得分:-2)
在发送和接收二进制数据时,还需要考虑客户端和服务器的字节序。
如果您的客户端是小端并发送到大端服务器,则在服务器上,如果客户端已将其转换为网络字节顺序,则无需转换二进制数据