【问题标题】:How to easily extract 2x int16 from a int32?如何从 int32 轻松提取 2x int16?
【发布时间】:2014-12-10 14:34:32
【问题描述】:

我有一个具有 2x int16 值的变量:

int32_t value = 0x1234ABCD; // a=0x00001234, b=0xFFFFABCD

天真的解决方案是做一个面具:

int32_t a = (value & 0xFFFF0000) >> 16;
int32_t b = (value & 0x0000FFFF);

但是有了这个,我没有任何符号扩展并且 b 变成 0x0000ABCD 而不是 0xFFFFABCD

我的下一个尝试是使用中间结构

struct dual_int16 {
   long hi:16;
   long lo:16;
}

int32_t a = (struct dual_int16)value).lo;
int32_t a = (struct dual_int16)value).hi;

不幸的是,我的编译器不允许我这样做“不允许使用 struct dual_int16”或“类型转换必须是算术或指针”。

是否有任何正确的方法可以在 C99 中通过符号扩展提取我的 2x int16?

编辑

因为我使用的是特定的编译器 (ADSP-21xxx) 。我没有在stdint.h 中定义的所有标准类型,例如int16_t。我的编译器无法识别int8_tint16_t

arch 有一个混合的 32-48 位双 ALU,大端。

【问题讨论】:

  • 在转换为 32 位之前,您是否尝试过转换为 int16_t
  • 您可能想尝试将 16 位值存储为 16 位类型。
  • 是什么让你认为0x1234ABCD & 0x0000FFFF 应该变成0xFFFFABCD
  • 您想要 int16 但将结果定义为 int32。结果正常。
  • @BennoZeeman 因为我存储了 2x int16。 0xABCD= -21555。如果您进行符号扩展,最终值将变为 0xFFFFABCD = -21555

标签: c


【解决方案1】:

如果您想要有符号的 16 位值,请使用正确的类型:

#include <stdint.h>

const int32_t value = 0x1234ABCD; // a=0x00001234, b=0xFFFFABCD

const int16_t a = (value >> 16) & 0xffff;
const int16_t b = value & 0xffff;

printf("a=%hd\nb=%hd\n", (short) a, (short) b);

打印出来:

a=4660
b=-21555

还要注意,我在遮罩之前进行了移位,以减小遮罩的字面大小。这对于现代智能优化编译器来说可能毫无意义,但这就是我改变它的原因。

我使用了int16_t,因为你使用了uint32_t并提到了C99,这真的让我相信你应该拥有它。确保你#include &lt;stdint.h&gt;

【讨论】:

  • 如果 OP 需要将它们存储到 int32_t,我想你可以通过 int32_t a = (uint16_t)((value &gt;&gt; 16) &amp; 0xffff);int16_t 隐式转换为 int32_t
  • 我真的没有得到(uint16_t) 的演员表,这不是你说你想做的……我对这个建议持怀疑态度。
  • 非常抱歉。我的意思是int16_t。我认为您在回答中提到 uint32_t 让我感到困惑。哦,亲爱的。
  • 关于减少文字大小,无论如何你都不想做(value &amp; 0xFFFFFFFF) &gt;&gt; 16,因为右移一个负整数是实现定义的行为:你不知道它是否会被零填充(逻辑移位)或带符号位(算术移位)。您编写的代码避免了此问题,因为您在 移位之后屏蔽了不需要的位。
  • @Lundin 是的,这也许是我很久以前切换到这种模式的另一个原因。 :) 谢谢。
【解决方案2】:

union 可以解决问题。

union {
    int32_t value;
    struct {
        int16_t v1, v2;
    } decomp;
} extract;

/* ... */
extract.value = value;
int32_t a = extract.decomp.v1, b = extract.decomp.v2;

请注意,ab 具有所需的符号。

【讨论】:

  • 可能会起作用,但比手动屏蔽和移位更多的工作和更容易出错。并非所有世界都是小端的。
  • @Deduplicator 是的。实际上在大端,它也可以解决问题。但v1v2 的顺序相反。不需要比手动移位更容易出错,因为它们实际上是相同的。
  • 永远不要读取已被其他成员写入的成员。
  • 您应该只阅读最近写入的字段。
  • C99, 6.2.6.1:“当一个值存储在联合类型对象的成员中时,对象表示中不对应于该成员但对应于其他成员的字节取未指定的值。”。我现在有点迷茫,但我很确定人们应该尽可能避免它。低层编程是不同的,因为通常你的目标是特定的架构等。
【解决方案3】:
short a = (short)( (value >> 16) & 0xFFFF );
short b = (short)( value & 0xFFFF );

int32_t 也不是标准类型(评论@coin)。 short/short int 等同于 int16_t

【讨论】:

  • int32_t 不是标准类型是什么意思? sizeof(short) 可能 > 2。
  • 可能是,也可能不是等效的。它是一个标准-typedef,如果实现有合适的类型,在C99中(并且可能向后移植)。
  • 这是来自上面的评论:“不幸的是,我的编译器不存在 int16_t”。出于这个原因,我说 int32_t 也不是普通类型。
猜你喜欢
  • 2019-03-05
  • 1970-01-01
  • 2021-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-07
  • 2011-08-22
  • 1970-01-01
相关资源
最近更新 更多