【问题标题】:Converting between unsigned and signed int safely安全地在 unsigned 和 signed int 之间转换
【发布时间】:2014-08-03 14:06:19
【问题描述】:

我在客户端和服务器之间有一个接口,客户端发送 (1) 一个无符号值,和 (2) 一个指示值是否有符号/无符号的标志。然后服务器会将无符号值静态转换为适当的类型。

我后来发现这是实现定义的行为,我一直在阅读它,但似乎找不到完全安全的合适解决方案?我读过类型双关语、指针转换和 memcpy。

简单地使用联合类型会起作用吗?一个包含有符号和无符号整数以及有符号/无符号标志的 UnionType。对于签名值,客户端设置联合的签名部分,服务器读取签名部分。未签名部分也是如此。还是我完全误解了什么?

附带问题:我如何知道在这种情况下针对特定场景的特定行为,例如PPC上的windriver diab?我对如何找到这样的文档有点迷茫。

【问题讨论】:

  • 除非您遇到使用诸如补码或符号幅度之类的系统,否则我认为您使用的所有内容都将以相同的方式定义无符号->有符号转换。
  • 当客户端发送无符号值但发送有符号标志时会发生什么?
  • 另外,您的代码是如何处理签名标志的? (由于 C++ 有一个静态类型系统,你需要在编译时分配你的类型)
  • @user2357112,这是否意味着对于二进制补码系统,static_cast(static_cast(x)) == x 总是成立?
  • @MattMcNabb,理想情况下服务器将 static_cast(unsigned_value) 并获得预期的签名值。还是您指的是发送联合类型的情况?签名标志只是一个布尔值,不确定我是否正确理解了您的第二个问题 - 刚刚编辑的争论

标签: c++ types casting int unsigned


【解决方案1】:

联合解决方案将要求您让客户端和服务器都使用相同的表示,这不是一个好主意。 (例如大端和小端系统都很常见)。

您应该以某种方式序列化该值。但是您只需为每种类型单独执行此操作。

例如(伪代码)

void send_signed(int32_t x)
{
    send(1, "s");
    send(sizeof x, serialized x);
}

void send_unsigned(uint32_t x)
{
     send(1, "u");
     send(sizeof x, serialized x);
}

在接收器上;你先读类型。如果它是“s”,那么你反序列化一个签名的 int 等等;如果它是“u”,那么你反序列化一个 unsigned int(到不同的变量)并用它做一些事情。

【讨论】:

  • 对于客户端和服务器端的字节序,用户需要做些什么吗?
  • 如果我们假设字节顺序不是问题,联合解决方案会起作用吗?
  • @Matt McNabb,serialized x 需要什么?只要发送“s”或“u”,我能找到的唯一要求就是将int x 转换为(unsigned int) x,比如unsigned int xmit = int whatever 并发送。然后在接收端,如果设置了's',则int rcvd = (int)xmit 负责签名。示例:int xmit = -5678 被发送为:` 11111111111111111110100111010010` 在接收到设置了 's' 时,int rcvd = (int)xmit 的转换恢复了另一端的正确符号:-5678。我还缺少什么吗? (x > 2,147,483,647 的情况不起作用,但是?
  • “序列化”是指将其以无损和可恢复的形式存储在数据中;例如我会先在两端存储一个 4 字节整数作为最高有效字节,但只要您可以在另一端恢复它,这并不重要。
【解决方案2】:

转换unsignedint 只是形式上有问题。在实践中,所有现存的平台都使用二进制补码表示,其中unsignedintintunsigned 完全相反(正式定义明确)。所以没有问题。


查看Wikipedia’s article on the UNIVAC 以了解使用补码表示的平台示例,例如用于 12 位和 36 位位字。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-24
    • 1970-01-01
    • 2011-07-02
    • 2020-04-08
    相关资源
    最近更新 更多