3

我正在尝试检查收到的消息编号是否在给定范围内。每次消息编号都会增加。因此,如果我期待 10 号,我接受任何编号为 10+ 5 的消息。所以序列号为 10 到 15。我使用的是无符号整数。因此,当预期数字为 65532 时,我可以接受 65532 + 10(所以 min = 65532 和 max = 5)。如何检查我收到的号码是否在此范围内?

4

3 回答 3

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;
}
于 2013-07-11T04:35:37.763 回答
1

如果你使用unsigned你得到某个值 k 的 GF(2 k ) 算术[编辑:加法和减法,做完整的有限域需要更多的工作;也许我应该采用其他一些速记术语?]。通常对于unsigned shortk 是 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 shortC 中的一个皱纹,它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 intunsigned short是明确定义的,因为它减少了值 mod 2 k)。

于 2013-07-11T04:40:49.503 回答
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");
}

如果您输入and和 ,这将失败。即使不在范围内,它也会打印“范围内”。incoming=5min=0xFFFFrange=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");
}
于 2013-07-11T05:38:12.307 回答