解释用C签名的无符号(长整数)int

在Arduino C:

我想重新解释无符号长整数的32位作为有符号长整数.完全相同的位,仅被视为2的补码整数,而不是无符号整数.我不认为简单地将它投射到(长)就可以了.我错了吗?

或许还有更好的方法.我使用unsigned long作为计时器.偶尔我会读取它的当前值并将其与之前的读数(两个无符号长度)进行比较,以查看已经过了多长时间.我需要处理一个可能的溢出,这会导致当前值比前一个值少.将这两个值解释为有符号长数并减去似乎给出正确答案.

我试过这个:

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

但只是有一个编译器错误:

Arduino:1.6.7(Mac OS X),主板:“Arduino Nano,ATmega328”
从’long unsigned int’类型转换为’long int’类型无效

最佳答案 关于通过比较两个未签名计数器来检查已经过了多少时间的更深层/原始问题,其中可能有一个单一的环绕:

简单地使用无符号算法从最新的中减去最早的.

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

return currTimeLo - time4;

这是因为C保证以2n为模执行无符号算术,其中n是无符号类型的值表示中的位数.

如果有超过1个回绕,这种方法将无效.在这种情况下,您需要使用数字范围较大的类型.

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

首先请注意,没有必要.它是X / Y问题中的Y.获得最新可能包含的两个计数器之间的差异是原始X,它有一个简单的解决方案(上图).

但是,因为这是标题中的问题:

据我所知,所有现存的C实现都是针对有符号整数使用2的补码表示的体系结构.

当原始值无法在该类型中表示时,Holy Standard™将其留给实现来定义转换为有符号整数类型的结果.任何合理的C实现都只是让你通过static_cast来实现.因此,

return static_cast<long>(time4) - static_cast<long>(currTimeLo);

但是无法保证Arduino中的编译器在这个问题上是合理的.

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

解决方法包括

>通过reinterpret_cast投射指针或引用,
>通过例如复制字节memcpy,正式安全但复杂且不必要的潜在低效,
>使用正式的UB联盟成员访问,或
>安全但复杂,将价值分割并重新组合.

最后一点可以用一种近乎优雅的方式完成,有人在早些时候发布了对这个问题的语言律师变体的回应.不幸的是,我不记得那个伎俩,只是因为它让我印象深刻,而我却没有想到这一点.但我推荐简单的static_cast,经过适当的测试.

点赞