C++ 将无符号(长)int解释为在C+中有符号+;

C++ 将无符号(长)int解释为在C+中有符号+;,c++,arduino,int,unsigned,signed,C++,Arduino,Int,Unsigned,Signed,我想将无符号长的32位重新解释为有符号长。完全相同的位,仅被视为2的补码整数,而不是无符号整数。我不认为简单地把它投到长就能奏效。我错了吗 或许有更好的办法。我正在使用一个未签名的长计时器。偶尔我会读取它的当前值,并将其与以前的读数(都是unsigned longs)进行比较,以查看经过了多少时间。我需要处理可能的溢出,这将导致当前值小于上一个值。将这两个值解释为有符号长和减法似乎给出了正确的答案 我试过这个: return reinterpret_cast<long>(time4)

我想将
无符号长
的32位重新解释为
有符号长
。完全相同的位,仅被视为2的补码整数,而不是无符号整数。我不认为简单地把它投到
就能奏效。我错了吗

或许有更好的办法。我正在使用一个未签名的长计时器。偶尔我会读取它的当前值,并将其与以前的读数(都是
unsigned long
s)进行比较,以查看经过了多少时间。我需要处理可能的溢出,这将导致当前值小于上一个值。将这两个值解释为有符号长和减法似乎给出了正确的答案

我试过这个:

return reinterpret_cast<long>(time4) - reinterpret_cast<long>(currTimeLo); // treat unsigned as 2's complement

您想使用
static\u cast
,类似于:

static_cast<signed long>(your_unsigned_long)
static\u cast(您的\u unsigned\u long)

关于通过比较两个无符号计数器(其中可能有一个单环绕计数器)来检查经过了多少时间这一更深层次的问题:

只需使用无符号算术从最早的减去最早的

假设您的
currTimeLo
是当前时间的计数器值,
time4
是某个较早的值,并且它们都是无符号类型(或者有符号类型的一个提升了另一个的无符号类型)

这是因为C++保证了无符号算术是以2n为单位执行的,其中n是无符号类型的值表示中的位数。 如果有超过1个环绕,这种方法将不起作用。在这种情况下,您需要使用具有更大数字范围的类型


关于问题标题将无符号值解释为2的补码有符号值的问题:

首先请注意,这不是必需的。这是X/Y问题中的Y。获取两个计数器之间的差异(最新的计数器可能已包装)是原始的X,它有一个简单的解决方案(如上所述)


但是,既然这是书名中提到的:

据我所知,所有现存的C++实现都是针对有符号整数使用2的补码表示的结构。 神圣的标准™ 当原始值不能在有符号整数类型中表示时,由实现定义强制转换为该类型的结果。任何合理的C++实现都只允许你通过<代码> STATICORCAST 进行。因此,

return static_cast<long>(time4) - static_cast<long>(currTimeLo);
returnstatic\u cast(time4)-static\u cast(currtimlo);
但是不能保证您的Arduino编译器在这方面是合理的

您必须对此进行检查,并在必要时使用相关选项,假设默认情况下行为不合理时可以进行调整

解决办法包括

  • 通过重新解释强制转换来强制转换指针或引用

  • 通过例如
    memcpy
    复制字节,形式上是安全的,但复杂且不必要的潜在低效

  • 使用正式的UB工会成员访问权限,或

  • 安全但复杂,将值拆分并重新组合


最后一点可以用一种近乎优雅的方式来完成,就像有人在回答早些时候这个问题的语言变体时所说的那样。不幸的是,我不记得那个把戏了,只是它给我留下了深刻的印象,因为它太明显了,但我没有想到。但是我推荐简单的
静态\u转换
,经过适当测试。

在2的补码中,有符号和无符号之间的简单转换有效,因为它将值包装为模2n,即将相同的位模式视为另一种类型。例如
(long)0xFFFFFFFFu
返回-1

然而,问题是加法和减法都会多产生1个进位/借位。该额外位必须与低32位一起存储在某个位置。因此,简单地将值强制转换为带符号的和减法并不适用于所有情况,尽管它适用于彼此距离不太远的值。尝试
LONG\u MAX-LONG\u MIN
LONG\u MIN-LONG\u MAX
查看结果如何不能存储在
LONG
中,即使两个操作数都是
LONG
s

要克服这一点,唯一的方法就是使用更广泛的类型

return static_cast<long long>(time4) - static_cast<long long>(currTimeLo);
如果在函数中使用它,则必须同时返回溢出进位和低32位差,因此第一种解决方案在32位或64位计算机上似乎更容易,第二种解决方案在8位MCU(如ATmega)上更快

如果可以保证两个操作数之间的距离永远不会超过
LONG\u MAX
,那么简单的
静态\u cast
到LONG将起作用

return static_cast<long>(time4) - static_cast<long>(currTimeLo);
returnstatic\u cast(time4)-static\u cast(currtimlo);

在我看来,同样的事情应该适用于无符号值。你不能检查一下第二个值是否比第一个值小吗?如果在正常情况下,新值比前一个值大,我可以简单地减去。但是当出现溢出时,新值小于上一个值,简单的减法不起作用。如果新值大于上一个值,我可以简单地减法。但是当出现溢出时,新值小于上一个值,简单的减法是不起作用的。使用8位值的示例:假设前一个值为0xFA(250位小数),新值为0x15(21位小数),因为计数器已溢出。考虑到这些是无符号值,我们将从15中减去250。如果使用无符号值得到负结果,我不确定会发生什么。把它们重新解释为有符号的值,我们从21减去6,给出27的正确答案。抱歉,我的意思是“考虑这些作为未签名的值,我们将从21减去250。”至少有一个国际公认的C++专家已经完成了你在这里做的事情,所以这不是一个只有新手参与的错误。我知道,因为我
return static_cast<long long>(time4) - static_cast<long long>(currTimeLo);
unsigned long timeDiff;
if (time4 > rcurrTimeLo) // time hasn't overflowed and time4 is later than rcurrTimeLo
{
    timeDiff = time4 - rcurrTimeLo;
    // do something, for example set overflow/later flag:
    later = 1;
}
else
{
    timeDiff = rcurrTimeLo - time4;
    // set "earlier" flag
    later = 0;
}
return static_cast<long>(time4) - static_cast<long>(currTimeLo);