我正在尝试检查收到的消息编号是否在给定范围内。每次消息编号都会增加。因此,如果我期待 10 号,我接受任何编号为 10+ 5 的消息。所以序列号为 10 到 15。我使用的是无符号整数。因此,当预期数字为 65532 时,我可以接受 65532 + 10(所以 min = 65532 和 max = 5)。如何检查我收到的号码是否在此范围内?
3 回答
简单地减去
unsigned message_number, expected_number;
unsigned range = 5; // or 10, OP’s post varies as to the desired range.
if ((message_number - expected_number) <= range) {
; // accept;
}
无符号算术的环绕是明确定义的。
[编辑]
如果message_number
环绕在与unsigned
. 以下解决方案没有做出这种假设,它们也没有假设 message_number 在unsigned short
.
unsigned maxsequenceplus1_number = 65536LU;
if (((message_number - expected_number)%maxsequenceplus1_number) <= range) {
; // accept;
}
const unsigned maxsequence_number = 65535U; // some power of 2 minus 1
if (((message_number - expected_number)&maxsequence_number) <= range) {
; // accept;
}
如果你使用unsigned
你得到某个值 k 的 GF(2 k ) 算术[编辑:加法和减法,做完整的有限域需要更多的工作;也许我应该采用其他一些速记术语?]。通常对于unsigned short
k 是 16,对于unsigned int
它是 32,对于unsigned long long
它是 64,但无论如何它至少是 16(因为UINT_MAX
至少是 65535)。
在这种有限域算术中,您可以简单地减去两个数字并将结果与您的极限进行比较。也就是说,如果“允许值”的范围是从 x 到 x+5,而您收到的实际值是 y,那么:
unsigned int x, y, diff;
...
diff = y - x;
if (diff <= 5) {
the value is in range
} else {
the value is out of range
}
只要“范围内”窗口不超过 2 k-1,就可以正常工作,并且由于 k >= 16 这意味着您的窗口空间至少为 32767。
如果您希望使用unsigned short
C 中的一个皱纹,它unsigned short
会扩展为 (signed, plain)int
而不是unsigned int
通常情况下的 when INT_MAX >= USHRT_MAX
。所以你必须转换unsigned int
为做减法:
unsigned short x, y, diff;
....
diff = (unsigned int)y - (unsigned int)x;
其余代码不变(请注意,分配unsigned int
回unsigned short
是明确定义的,因为它减少了值 mod 2 k)。
要使用 16 位整数(即范围 0 到 65535)获得正确的结果,您可以使用unsigned short
来存储这些值。然后翻身就可以了。
但是你需要小心。仅仅因为您将所有变量都声明为unsigned short
,实际上 2 之间的差异unsigned shorts
可以自动转换为int
,这将破坏您的代码。
例如,
void test(unsigned short incoming, unsigned short min, unsigned short range)
{
if ((incoming - min) >= 0 && (incoming - min) < range)
printf("in range");
else
printf("out of range");
}
如果您输入and和 ,这将失败。即使不在范围内,它也会打印“范围内”。incoming=5
min=0xFFFF
range=5
要解决此问题,您需要执行
void test(unsigned short incoming, unsigned short min, unsigned short range)
{
if ((unsigned short)(incoming - min) >= 0 &&
(unsigned short)(incoming - min) < range)
printf("in range");
else
printf("out of range");
}
这是c语言中一个有争议的点。该规范允许在大于给定数据大小(短)的寄存器中执行减法。大多数计算机都有 32 位或 64 位寄存器,因此减法是由带int
符号的寄存器执行的。所以 0x00000005 - 0x0000FFFF = 0xFFFF0006,它是负数 (-65530) 而不仅仅是 6。您需要重新转换回原始数据类型(无符号短)才能取回 6。
请参阅在存在 unsigned int 和 signed int 的 C 表达式中,哪种类型将提升为哪种类型?讨论整数提升。
您也可以这样做,这可能是最好的答案。我拿出了比较,delta >= 0
因为对于无符号整数来说总是如此。并且还切换到使用
stdint.h
#include <stdint.h>
void test(uint16_t incoming, uint16_t min, uint16_t range)
{
uint16_t delta = incoming - min;
if (delta < range)
printf("in range");
else
printf("out of range");
}