如何在无符号操作数之间执行有符号比较?

时间:2017-09-07 21:47:20

标签: c casting integer unsigned signed

我已声明了4个无符号变量:

uint32_t empty_bucket;
uint32_t base_bucket;
uint32_t hop_size;
uint32_t ht_size;

我想执行签名条件检查:

if (empty_bucket < base_bucket + (hop_size - 1) - ht_size)

知道base_bucket + (hop_size - 1) - ht_size可能是负值。操作员执行此操作的正确铸造是什么?

注意: base_bucket + (hop_size - 1) - ht_size可能非常接近-2^32,因此转换为带符号的32位int32_t可能会导致溢出。

2 个答案:

答案 0 :(得分:4)

由于您正在使用stdint include,您可以将操作数转换为64位有符号值,并对此进行比较,不会有任何右边的任何条件成为负数的风险,我们必须强制转换左操作数到有符号整数,以避免在比较signed / unsigned时的未定义/实现行为:

if ((int64_t)empty_bucket < ((int64_t)base_bucket + ((int64_t)hop_size - 1) - (int64_t)ht_size))

总结一下:

  • 没有溢出的风险(我可能在右侧投入太多)
  • 签名实体之间的比较
  • 缺点是,64位转换可能会对32位架构的性能产生负面影响

答案 1 :(得分:3)

if (base_bucket + hop_size > ht_size + 1
    && empty_bucket < base_bucket + (hop_size - 1) - ht_size)

第一行检查我们想要执行的比较的右侧是否确实是正整数。通过检查所有正值(base_buckethop_size)是否大于所有负值(- 1- ht_size)来完成。它不使用减法就可以做到这一点,因此使用无符号整数是安全的。

@David Bowling建议

if (empty_bucket + ht_size < base_bucket + (hop_size - 1)) 

这个想法基本相同,以确保比较的双方始终是积极的。如果base_buckethop_size不是同时为零,则此方法有效。

使用这两种解决方案理论上仍然可能存在溢出,您必须使用实际值进行检查。如果有溢出,请使用更大的类型。

请忽略我之前提到的短路评估,因为它不相关。如果整数大小为“正常”,例如。 16,32或64位,这应该可行。