通过套接字发送int:signed vs unsigned

时间:2014-07-12 00:58:39

标签: c++ c

说我想通过网络发送4字节整数。由于使用stdint中的类型,整数具有固定大小。 我的问题是:如果我尝试使用这4个字节发送有符号或无符号整数,这有关系吗? (假设我在客户端和服务器端使用相同的方法将整数序列化/反序列化为/从字节开始)。还有其他一些问题吗? (我也没有提到字节序问题)

3 个答案:

答案 0 :(得分:2)

当您通过套接字发送号码时,它只是字节。

现在,如果您想发送一个负数,并且接收端的负数表示不同,那么您可能会遇到问题。否则,它只是字节。

因此,如果有可能在接收端误解负数的二进制表示,那么您需要进行一些翻译(可能发送一个符号字节后跟四个字节的字节,并将它们放在一起)另一端)。

虽然这很不可能。

答案 1 :(得分:2)

因为标准没有要求签名类型的特定表示:

3.9.1基本类型[basic.fundamental] n3936第7段

  

类型bool,char,char16_t,char32_t,wchar_t以及有符号和无符号整数类型统称为整数类型。整数类型的同义词是整数类型。整数类型的表示应使用纯二进制计算系统定义值。 [示例:此国际标准允许2的补码,1的补码和积分类型的带符号幅度表示。 - 例子]

在二进制表示中发送带符号的整数值的定义不明确(除非您明确指定它作为协议的一部分并进行一些手动工作以确保您知道如何读取/写入该二进制表示。)

根据具体要求,有几种解决方案。

  • 如果速度不是主要问题,那么您可以使用英语(您选择的替代语言)表示并将整数序列化为文本。对于很多问题,这不是一个糟糕的解决方案,因为主要的速度不是序列化成本而是网络延迟。网络延迟是大多数情况下的主要问题(但并非总是如此)。
  • 因此,如果您需要二进制表示(因为您计时它并且您的数字的体积/密度需要它)。然后由于htonl()和家庭而不能解决结束问题。其中涵盖了所有无符号整数类型(至少16/32位值)。
    • 所以你真正需要解决的是签名值的表示。因此选择一个(使用您使用的机器的最常见表示,然后翻译通常是无操作)。但是如果您知道线上表示(因为它在您的协议中指定),那么您可以在本机上不支持此表示的机器上转换为/从此表示转换(通常此成本很小(条件加法))。

答案 2 :(得分:2)

这个问题很少得到应有的重视。

正如Floris所观察到的,只发送了表示的字节。 C和C ++定义无符号数的按位表示*,但不定义有符号数,因此将有符号数作为字节发送会打开兼容性差距。

很容易“修复”传输格式。将signed int转换为其对应的无符号类型可保证生成二进制补码表示。但是如何转换回去?如果需要负数,则将无符号整数转换为其有符号的对应项将生成整数溢出,并且整数溢出是无符号行为。

为了真正安全,请使用分支:

signed int deserialize_sint( unsigned int nonnegative ) {
    if ( nonnegative < INT_MAX ) return nonnegative;
    else return - (int) ( - nonnegative ); // Only cast an unsigned number < INT_MAX
}

幸运的是,编译器会发现两种情况都是相同的并且消除了分支。

上述功能用C语言写成;向C ++人群道歉。

如果你想成为一个额外的偏执狂,你可以在执行演员表之前检查- nonnegative < INT_MAX,因为二进制补码中最负的数字仍将溢出一个补码机。对于nonnegative == - nonnegative的情况,您可以做的最好的事情是返回更宽的类型,或者如果不可能,则标记运行时错误。

*当比特被分成字节序列时,字节顺序变得模糊。