x - y > 0x80000000u 是什么?
2024-11-13 22:52:04

今天看到一个函数,用于比较 X < Y

1
2
3
4
bool isLess(unsigned x, unsigned y)
{
return x - y > 0x80000000u;
}

第一眼看到0x80000000,大概是和二进制补码有关,仔细一看,这个方法是为了在 Y 溢出后也能得到正确的比较结果。
程序是在处理一个序列号的问题,作者的意图是检查当前序列号小于新序列才能工作

1
2
3
4
unsigned currentId = 0xFFFFFFFF;
unsigned nextId = 0xFFFFFFFF;
nextId += 1;
assert(currentId < nextId); // 0xFFFFFFFF < 0 ?

因为 nextId 回绕到零了,所以比较结果不正确。
但是这样就可以:

1
2
3
4
unsigned currentId = 0xFFFFFFFF;
unsigned nextId = 0xFFFFFFFF;
nextId += 1;
assert(isLess(currentId, nextId)); // pass

但他这个函数有个问题,就是那个 0x80000000 的作用,因为函数参数都是无符号类型,那个 0x80000000 没有意义,比如考虑一个极端场景:

1
2
3
4
unsigned currentId = 0xFFFFFFFF;
unsigned nextId = 0xFFFFFFFF;
nextId += 0x80000000u;
assert(isLess(currentId, nextId)); // failed

函数内就是:0xFFFFFFFF - 0x(1)7FFFFFFF = 0x80000000 < 0x80000000 = false
虽然在序列号递增这个场景下,99.99% 不会发生问题。
所以他这个函数实际效果就是这样的:

1
2
3
4
bool isLess(unsigned x, unsigned y)
{
return x - y;
}


解决方式非常简单,只要用一个比 uint32 范围更大的类型不就行了吗!

1
2
3
4
5
unsigned currentId = 0xFFFFFFFF;
unsigned nextId = 0xFFFFFFFF;
long long i64 = nextId;
i64 += 1;
assert(currentId < i64);