我可以通过网络发送二进制形式的整数,而不必担心陷阱值中的UB吗?

时间:2017-05-02 10:38:40

标签: c posix language-lawyer undefined-behavior

坦率地说,这样的代码是否有效(除了缺少必要的错误检查,为简单起见,这里省略了)?

通过互联网发送数据的代码:

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_tuint32_t不会有陷阱值?

或者它不受任何官方标准的保证,但是绝大多数实现没有uint16_tuint32_t的陷阱值,因此根据这个事实上的标准,我不这样做不得不害怕这个?

4 个答案:

答案 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)

在发送和接收二进制数据时,还需要考虑客户端和服务器的字节序。

如果您的客户端是小端并发送到大端服务器,则在服务器上,如果客户端已将其转换为网络字节顺序,则无需转换二进制数据