c - 是否通过强制转换为已签名的未定义行为来检测未签名的环绕?

标签 c casting undefined-behavior

我正在使用 uint16_t作为网络协议(protocol)中的序列计数器。该计数器通常按预期环绕。当接收方收到数据包时,它会根据最近收到的数据检查此计数器,以查看它是新数据包还是乱序数据包。

比较序列号时需要考虑环绕。因此,例如,如果最后一个序列号是 0x4000 ,然后是来自 0x4001 的序列号至 0xBFFF较新,序列号来自 0xC0000xFFFF来自 0x00000x3FFF更小。

我目前的做法是这样的:

uint16_t last;
uint16_t current;
...
// read in values for last and current
...
if ((int16_t)(current - last) > 0) {
    printf("current is newer\n");
} else {
    printf("current is older (or same)\n");
}

将两者相减并将结果视为 int16_t ,我可以很容易地看出哪个更大以及有多少。因此,例如,如果当前序列号至少比最后一个序列号少 5,即 ((int16_t)(current - last) < -5) ,我可以假设这不是由于正常的数据包重新排序和丢弃数据包。

我意识到有符号环绕是未定义的,但是在这种情况下,为了进行比较,我将无符号值视为有符号值。这是否会调用未定义的行为,如果是,执行此类比较的更好方法是什么?

最佳答案

超出范围的转换行为是实现定义的

你为什么不完全避免这个问题并写下:

if ( current != last && current - last < 0x8000 )
    printf("current is newer\n");
else
    printf("current is older (or same)\n");

注意:此答案仅适用于涉及uint16_t 的特定问题。对于其他类型,将需要不同的代码。

关于c - 是否通过强制转换为已签名的未定义行为来检测未签名的环绕?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31967370/

相关文章:

sql - 转换与转换 SQL Server

c - 重复文件查找算法的建议(使用 C)

c - 解析中的段错误

java - Android 上的多处理

qt - 如何将 QChar 转换为 int

c - 具有灵活数组成员的结构体的 “Array”

c - 取消引用 void**-casted type** 会打破严格的别名吗?

c++ - 在生产中使用 Address Sanitizer 或其他未定义的行为 sanitizer ?

c - 预增量和后增量

c - 如果我在 fork 之前在一个进程上注册了一个自定义信号处理程序,后续的子进程是否也会注册该自定义信号处理程序?