【问题标题】:how to retrieve a signed value stored in unsigned variable如何检索存储在无符号变量中的有符号值
【发布时间】:2016-10-09 19:34:00
【问题描述】:

我有一个有符号的 8 位值(二进制补码)存储在一个无符号的 uint8_t 变量中。 发生这种情况是因为该值是通过 spi 接口从外部外围设备读取的,例如:

uint8_t return_value = read_spi(uint8_t register_address)

外设的数据表表明该特定地址包含二进制补码值,因此 return_value 内的位模式应该是有符号的 8 位值。

我知道检索有符号值的明显方法:去掉符号位,如果为负翻转位,则加 1,乘以 -1。

我想知道是否有更优雅的方式。

【问题讨论】:

  • 如果您在寄存器中的值是有符号值,您只需将其作为有符号值处理,无需进行转换,简单的转换就足够了。用于读取外围寄存器的通用例程以允许读取任何值的方式编写。这类似于缓冲区读取,其中缓冲区被定义为通用字符,然后分配给结构或其他东西。你要做的很简单:int8_t MyVar = (int8_t)read_spi(RegAddr);
  • int8_t MyVar = (int8_t)read_spi(RegAddr);我同意这可能有效,正如 user694733 所说,但从任何角度来看,这不是类型转换吗?
  • 为什么不是类型转换?演员表操作员就在那里:(int8_t)。为什么这很重要?这种转换定义明确、安全且可移植。
  • 您不需要算术运算来检索带符号的值 - 它只是对 same 位模式的重新解释 - 将其分配给带符号的类型(带或不带显式转换)并继续。

标签: c integer embedded type-conversion


【解决方案1】:

在 C 语言中,您可以通过 union 键入双关。

union foo
{
    uint8_t ui;
    int8_t i;
} f;

设置f.ui = return_value,然后使用f.i读回带符号的值。

【讨论】:

  • 你的意思是“双关语”而不是“修剪”
  • 糟糕。今晚我会让我 2 岁的孩子给我读书。让我们重新学习英语!
  • 我喜欢type-pruning这个词——我会找到它的用途! ;-)
  • 这对我来说甚至是有意义的,我认为它会修剪符号位:)
【解决方案2】:

如果你是补码系统,你可以这样做:

int8_t result = return_value;  // or assign the from function directly

严格来说,当值为负时,行为是实现定义(N1570,6.3.1.3):

  1. 当整数类型的值转换为_Bool以外的其他整数类型时,如果该值可以用新类型表示,则保持不变。
  2. ...
  3. 否则,新类型是有符号的,值不能在其中表示;结果是实现定义的,或者引发了实现定义的信号。

在实践中,它确实有效; intN_t 类型保证是二进制补码并且没有填充位。典型的现代机器不会费心对无符号到有符号的赋值执行任何额外的操作,而只是复制位。如果您想确定,请查看您的编译器手册。

【讨论】:

  • 字符类型不能有填充位(C 标准明确禁止),stdint 类型也不能有填充位 - 它们保证是二进制补码。
猜你喜欢
  • 1970-01-01
  • 2020-08-09
  • 2016-08-27
  • 1970-01-01
  • 2014-04-15
  • 2010-09-29
  • 1970-01-01
  • 1970-01-01
  • 2019-11-06
相关资源
最近更新 更多