我正在尝试检查收到的消息号是否在给定范围内。每当消息号增加时。如果我期待数字10,我接受任何号码为10+的消息。所以序列号为10到15.我使用的是unsigned int。因此,当预期数量为65532时,我可以接受65532 + 10(所以min = 65532和max = 5)。如何检查我收到的号码是否在此范围内?
答案 0 :(得分:6)
简单地减去
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;
}
答案 1 :(得分:1)
如果使用unsigned
,你会得到GF(2 k )算术的某个值k [编辑:加法和减法,完整的有限域是更多的工作;也许我应该采用其他一些简写术语?]。通常,unsigned short
k为16,unsigned int
为32,而unsigned long long
为64,但无论如何至少为16(因为UINT_MAX
为至少65535)。
在这种finite field arithmetic中,您可以简单地减去两个数字,并将结果与您的限制进行比较。也就是说,如果“允许值”的范围是从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
在通常情况下扩展为(已签名,普通)int
而非unsigned int
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 的值。
答案 2 :(得分:1)
要使用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");
}
如果您输入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。
有关整数提升的讨论,请参阅In a C expression where unsigned int and signed int are present, which type will be promoted to what type?。
你也可以这样做,这可能是最好的答案。我取出了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");
}