且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在不损失结果范围的情况下将C中的uint转换为int

更新时间:2023-11-24 19:50:52

必须有一个标准函数可以执行此操作……但与此同时:

There must be a standard function that does this... but in the meantime:

#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,但问题是确定的.

Note that it is UB in the case that the result is not representable, but the question said that was OK.

如果系统具有64位long long类型,则可以轻松地自定义和检查范围:

If the system has a 64-bit long long type, then the range can easily be customized and checked as well:

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位类型.

With the range customization, this solution minimizes range loss in all situations, assuming timestamps behave linearly (for example, no special meaning to wrapping around 0) and a singed 64-bit type is available.