我想要两个无界整数之间的差异,每个整数都由一个uint32_t
值表示,该值是取2 ^ 32为模的无界整数。如,例如,TCP序列号。请注意,模2 ^ 32表示形式可以环绕0,这与不允许绕0环绕的更严格的问题不同。
假定基础无界整数之间的差在正常范围内int
。我想要这个带符号的差异值。换句话说,返回一个正常int
范围内的值,该值等于两个uint32_t输入模2 ^ 32之差。
例如,0 - 0xffffffff = 1
因为我们假设基础无界整数在int
范围内。证明:如果A mod 2 ^ 32 = 0且B mod 2 ^ 32 = 0xffffffff,则(A = 0,B = -1)(mod 2 ^ 32)因此(AB = 1)(mod 2 ^ 32)和在int
此模级的范围内,具有单个代表1
。
我使用了以下代码:
static inline int sub_tcp_sn(uint32_t a, uint32_t b)
{
uint32_t delta = a - b;
// this would work on most systems
return delta;
// what is the language-safe way to do this?
}
这在大多数系统上都有效,因为它们对uint
和都使用modulo-2 ^ 32表示形式int
,并且正常的modulo-2 ^ 32减法是在此处生成的唯一合理的汇编代码。
但是,我相信C标准仅在的情况下定义上述代码的结果delta>=0
。例如关于这个问题的一个答案说:
如果将超出范围的值分配给带符号类型的对象,则结果不确定。该程序似乎可以运行,崩溃或可能产生垃圾值。
应该如何从模2 ^ 32转换uint
到int
根据C标准做什么?
注意:我希望答案代码不包含条件表达式,除非您可以证明它是必需的。(在代码说明中进行案例分析就可以了)。
必须有一个执行此操作的标准函数...但与此同时:
#include <stdint.h> // uint32_t
#include <limits.h> // INT_MAX
#include <assert.h> // assert
static inline int sub_tcp_sn(uint32_t a, uint32_t b)
{
uint32_t delta = a - b;
return delta <= INT_MAX ? delta : -(int)~delta - 1;
}
请注意,如果结果无法表示,则为UB,但问题是可以的。
如果系统具有64位long long
类型,则范围也可以轻松自定义和检查:
typedef long long sint64_t;
static inline sint64_t sub_tcp_sn_custom_range(uint32_t a, uint32_t b,
sint64_t out_min, sint64_t out_max)
{
assert(sizeof(sint64_t) == 8);
uint32_t delta = a - b;
sint64_t result = delta <= out_max ? delta : -(sint64_t)-delta;
assert(result >= out_min && result <= out_max);
return result;
}
例如,sub_tcp_sn_custom_range(0x10000000, 0, -0xf0000000LL, 0x0fffffffLL) == -0xf00000000
。
通过范围自定义,该解决方案在所有情况下都将范围损失降到最低,假设时间戳是线性运行的(例如,对0环绕没有特殊含义),并且可以使用单个64位类型。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句