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);