【问题标题】:Merge uint16_t and int16_t into int32_t for data transmission in CC中将uint16_t和int16_t合并成int32_t进行数据传输
【发布时间】:2019-12-05 12:42:20
【问题描述】:

我遇到了问题,以 int32_t 类型传输索引(uint16_t)和数据(int16_t),但我还没有成功。

我尝试的是以下内容:

int32_t buf = (int16_t) data;
buf |= ((int32_t idx)<<16);

但这仅适用于正数据,因为 2 补码会在 MSB 处加一。我怎样才能做到这一点?

【问题讨论】:

  • buf 应该是 uint32_t。 buf = data &amp; 0xffff;

标签: c types


【解决方案1】:

试试:

uint32_t buf = data & 0xffff; 
buf |= idx<<16;

【讨论】:

  • 这在 unsigned int 为 16 位的实现中失败,因为 idx&lt;&lt;16 是在 unsigned int 算术中评估的,并且移位 16 将是未定义的。它在 int 为 32 位的实现中失败,因为 idx&lt;&lt;16 是在 int 算术中评估的,如果设置了它的高位(第 15 位),则会溢出。
【解决方案2】:

由于整数提升、整数表示和位移定义的限制等细节问题,在 C 中合并整数类型是一个臭名昭著的问题。

首先,很少有充分的理由将uint16_t 和int16_t 合并到int32_t 中进行传输。应该使用unsigned char * 简单地访问对象的字节并传输字节。通常,使用memcpy 可以轻松地将字节收集到缓冲区中进行传输,这相当于使用unsigned char * 复制字节。

如果您必须将uint16_t 和int16_t 合并为int32_t,前者进入高字节,那么符合标准的方法是:

uint32_t temporary = (uint32_t) idx << 16 | (uint16_t) data;
int32_t buf;
memcpy(&buf, &temporary, sizeof buf);

解释:

  • (uint32_t) idx 将idx 加宽到 32 位,确保它可以移动 16 位而不会丢失任何数据。
  • (uint16_t) data 将 data 从 int16_t 转换为 16 位的非负值,当扩展为 32 位时,该值将保持非负(并且不受符号扩展的影响)。
  • 然后将这两部分组装成一个uint32_t。 (一般来说,使用无符号整数处理位操作更容易,因为它们在 C 中对位操作的语义比有符号整数更好。)
  • 最后,将生成的位复制到buf,避免有符号整数溢出和转换的问题。

Note that a good compiler will optimize away the memcpy.

要在没有memcpy 的情况下执行此操作,本质上需要将uint16_t 调整为有符号值:

int32_t temporary = 0x8000 <= idx ? idx - 0x10000 : idx;
int32_t buf = temporary << 16 | (uint16_t) data;

或者,如果data和idx在buf中的顺序可以改变,一个更简单的解决方案是:

int32_t buf = data * 65536 | idx;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-22
    • 2015-05-25
    • 2021-11-16
    • 2014-12-24
    相关资源
    最近更新 更多