【问题标题】:Convert 8 bit signed integer to unsigned and then convert to int32将 8 位有符号整数转换为无符号整数,然后再转换为 int32
【发布时间】:2021-11-09 14:52:29
【问题描述】:

我有一个带符号的 8 位整数 (int8_t) -- 它可以是从 -55 的任何值 -- 并且需要将其转换为无符号的 8 位整数 (uint8_t) .

这个uint8_t 值随后会被传递到另一块硬件(只能处理 32 位类型)并且需要转换为 int32_t

我该怎么做?

示例代码:

#include <stdio.h>
#include <stdint.h>

void main() {

    int8_t input;
    uint8_t package;
    int32_t output;

    input = -5;
    package = (uint8_t)input;
    output = (int32_t)package;

    printf("output = %d",output);
}

在本例中,我以-5 开头。它暂时被转换为251,因此可以打包为uint8_t。然后,此数据被发送到另一块硬件,在该硬件中我无法使用 (int8_t) 将 8 位无符号整数转换回有符号,然后再转换为 int32_t。最终,我希望能够获得原始的-5 值。

有关详细信息,接收硬件是 SHARC 处理器,它不允许 int8_t - 请参阅 https://ez.analog.com/dsp/sharc-processors/f/q-a/118470/error-using-stdint-h-types

SHARC 处理器上最小的可寻址内存单元是 32 位,这意味着任何数据类型的最小大小都是 32 位。这适用于原生 C 类型,如 char 和 short。因为类型“int8_t”、“uint16_t”指定类型的大小必须分别为8位和16位,所以SHARC不支持。

【问题讨论】:

  • 这真的取决于你所说的“转换”是什么意思。当您将int8_t 转换为uint8_t 时,您期望-5 变成什么?在您当前的代码中,它变为251
  • 这里真正的问题是,为什么要先通过uint8_t?因为要保留一个无符号的 8 位值,然后将其扩展到 32 位?
  • 感谢您的评论 - 这与硬件限制有关。我正在将数据从一个硬件发送到另一个。所有数据都需要以无符号整数 8 位包的形式发送。但是我收到的硬件不允许我在转换为 int32_t 之前转换为 (int8_t)
  • 你必须通过几个例子来阐明你希望你的最终结果是什么,我们不能只是猜测你想要做什么。当 -5 最终转换为 int32_t 时,您是否希望 -5 保持不变?
  • 看来你的要求很混乱。硬件通常不需要带符号的数字。您要解决的实际问题是什么?您是否正在尝试发明一种数据通信协议?然后需要为该协议指定签名和字节序等,并且每个使用它的 CPU 都必须转换到该协议/从该协议转换。

标签: c integer


【解决方案1】:

这是一种可能的无分支转换:

output = package; // range 0 to 255
output -= (output & 0x80) << 1;

如果设置了第 7 位,第二行将减去 256,例如:

  • 251 设置了第 7 位,251 - 256 = -5
  • 5 已清除第 7 位,5 - 0 = 5

【讨论】:

  • 我宁愿检查符号扩展指令并将其用作内在。这些处理器以最高效方式编程,忽略了可移植性。
【解决方案2】:

如果您想使用 32 位操作恢复负号,您可以执行以下操作:

   output = (int32_t)package;
   if (output & 0x80) { /* char sign bit set */
        output |= 0xffffff00;
   }

   printf("output = %d",output);

【讨论】:

    【解决方案3】:

    由于您的接收器平台没有小于 32 位宽的类型,您最简单的选择是在发送器上解决此问题:

    int8_t input = -5;
    int32_t input_extended = input;
    uint8_t buffer[4];
    
    memcpy(buffer, &input_extended, 4);
    
    send_data(buffer, 4);
    

    然后在接收端您可以简单地将数据视为单个int32_t

    int32_t received_data;
    
    receive_data(&received_data, 4);
    

    所有这些都假设您的发送者和接收者共享相同的endianness。如果没有,您将不得不在发送前翻转发送方的字节序:

    int8_t input = -5;
    int32_t input_extended = input;
    uint32_t tmp = (uint32_t)input_extended;
    
    tmp = ((tmp >> 24) & 0x000000ff)
        | ((tmp >>  8) & 0x0000ff00)
        | ((tmp <<  8) & 0x00ff0000)
        | ((tmp << 24) & 0xff000000);
    
    uint8_t buffer[4];
    
    memcpy(buffer, &tmp, 4);
    
    send_data(buffer, 4);
    

    【讨论】:

      【解决方案4】:

      只需从值中减去 256,因为在 2's complement 中,一个 n 位负值 v 存储为 2n - v

      input = -5;
      package = (uint8_t)input;
      output = package > 127 ? (int32_t)package - 256 : package;
      

      【讨论】:

        【解决方案5】:

        编辑:

        如果问题是您的代码有 -55 的值的 if 语句,那么最简单的解决方案可能是测试 result + 5 并将 if 语句更改为 @987654326 之间的值@和10

        这可能是编译器在优化时会做的事情(因为可以将 0-10 的值转换为映射,避免 if 语句并最大限度地减少预测性 CPU 刷新)。


        原文:

        如果先转换为uint8_t,然后再转换为uint32_t,则类型转换将起作用...

        output = (int32_t)(uint32_t)(uint8_t)input;
        

        当然,如果设置了第 8 位,它将保持设置状态,但符号不会被扩展,因为类型转换操作告诉编译器将第 8 位视为常规位(它是无符号的)。

        当然,如果您想更加严格,您可以随时享受位掩码的乐趣,但这本质上是浪费或 CPU 周期。

        代码:

        #include <stdint.h>
        #include <stdio.h>
        
        void main() {
        
          int8_t input;
          int32_t output;
        
          input = -5;
          output = (int32_t)(uint32_t)(uint8_t)input;
        
          printf("output = %d\n", output);
        }
        

        结果为“output = 251”。

        【讨论】:

          猜你喜欢
          • 2012-01-11
          • 2012-01-09
          • 1970-01-01
          • 2017-07-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-02-20
          相关资源
          最近更新 更多