在系统实现中,经常需要用到序列号来记录操作执行的顺序或者打印时间戳等。因为序列号等我们只取正值,所以一般都使用无符号数以表示更大的范围。虽然一般的32位或者64位无符号数表示的范围很大,甚至可以确保在系统的生命周期内都不会用完,但是作为一个健壮的系统还是需要考虑无符号数达到最大后,重新归零的溢出问题。
此时有一个比较简单的转换可以用来规避该问题。在比较两个序列号的大小时,使用以下 before 内联函数即可,如果 seq1 小于 seq2 将返回正数,如果 seq1 大于等于 seq2 将返回负数。
static inline int before(uint32_t seq1, uint32_t seq2)
{
return (int32_t)(seq1 - seq2) < 0;
}
乍一看,将两个 uint32_t 相减的结果转换为 int32_t 之后会有溢出的问题,因为一个很大的32位无符号整数减去一个很小的32位无符号整数,在转换后会变成负数。而这正是解决无符号数溢出问题的关键。此处隐含了一个默认的前提,即在使用 before 函数判断序列号时,需要保证进行判断的序列号是相邻出现的,至少其差异不会跨越整个无符号数表示范围的一半,这也常常是符合我们使用序列号的习惯的。这样即使无符号数溢出真的发生了,我们通过 before 函数进行序列号比较时,就仍能得到正确的结果。