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

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

本文介绍了如何在不损失结果范围的情况下将C中的uint转换为int的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要两个无界整数之间的差,每个整数都由一个uint32_t值表示,该值是取2 ^ 32为模的无界整数.如,例如,TCP序列号.请注意,模2 ^ 32 表示形式可以环绕0,而不像更多受限制的问题,即不允许环绕0 .

I want the difference between two unbounded integers, each represented by a uint32_t value which is the unbounded integer taken modulo 2^32. As in, for example, TCP sequence numbers. Note that the modulo 2^32 representation can wrap around 0, unlike more restricted questions that do not allow wrapping around 0.

假定基础无界整数之间的差在正常int的范围内.我想要这个带符号的差异值.换句话说,返回正常int范围内的值,该值等于两个uint32_t输入以模2 ^ 32为模的差.

Assume that the difference between the underlying unbounded integers are in the range of a normal int. I want this signed difference value. In other words, return a value within the normal int range that is equivalent to the difference of the two uint32_t inputs modulo 2^32.

例如,0 - 0xffffffff = 1,因为我们假定基础无界整数在int范围内.证明:如果A mod 2 ^ 32 = 0且B mod 2 ^ 32 = 0xffffffff,则(A = 0,B = -1)(mod 2 ^ 32)因此(AB = 1)(mod 2 ^ 32)和在int范围内,此模数类具有单个代表1.

For example, 0 - 0xffffffff = 1 because we assume that the underlying unbounded integers are in int range. Proof: if A mod 2^32 = 0 and B mod 2^32 = 0xffffffff, then (A=0, B=-1) (mod 2^32) and therefore (A-B=1) (mod 2^32) and in the int range this modulo class has the single representative 1.

我使用了以下代码:

static inline int sub_tcp_sn(uint32_t a, uint32_t b)
{
    uint32_t delta = a - b;

    // this would work on most systems
    return delta;

    // what is the language-safe way to do this?
}

这在大多数系统上都有效,因为它们对uintint都使用modulo-2 ^ 32表示形式,并且普通的modulo-2 ^ 32减法是在此处生成的唯一合理的汇编代码.

This works on most systems because they use modulo-2^32 representations for both uint and int, and a normal modulo-2^32 subtraction is the only reasonable assembly code to generate here.

但是,我相信,如果delta>=0,则C标准仅定义上述代码的结果.例如,在这个问题上一个答案说:

However, I believe that the C standard only defines the result of the above code if delta>=0. For example on this question one answer says:

如何根据C标准将uint转换为int的2 ^ 32模数?

How should a modulo-2^32 conversion from uint to int be done according to the C standard?

注意:我希望答案代码不包含条件表达式,除非您可以证明它是必需的. (在代码说明中进行案例分析就可以了.)

Note: I would prefer the answer code not to involve conditional expressions, unless you can prove it's required. (case analysis in the explanation of the code is OK).

推荐答案

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

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.

这篇关于如何在不损失结果范围的情况下将C中的uint转换为int的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-30 22:22