如何将* signed * 24位int存储到另一个变量中?

时间:2016-10-15 20:29:12

标签: c++ c bit-manipulation

我需要将24位整数编码到32位int的末尾。

(第一个字节包含其他数据,其他三个空为24位int使用)

我已经有一个SET_BYTE宏,我可以为无符号 24位值成功执行以下操作:

SET_BYTE(DEST, START_BYTE_INDEX,   (uint8_t)(VALUE)); 
SET_BYTE(DEST, START_BYTE_INDEX+1, (uint8_t)(VALUE >> 8)); 
SET_BYTE(DEST, START_BYTE_INDEX+2, (uint8_t)(VALUE >> 16)); 

我坚持的是,我不太确定如何修改此方法以使用签名 24位整数?

如果我尝试用上面的值存储值-22(显然是修改为使用int8_t),例如,我得到以下字节值:

-22
-1
-1

以这些方式回读(如果我在阅读时<<0<<8<<16):

-22
-256
-65536

我假设我只需要用签名值完全避免这些转变,但我不确定正确的方法是什么?

3 个答案:

答案 0 :(得分:1)

如果你需要一个≥32位的结构(如你所说,你在最后一个字节中有其他数据)使用struct bitfields:

struct Packed
{
    uint8_t byte;
    int32_t smaller : 24;
};

或者,您可以滥用std::bitset

struct fake_int24_t
{
    static_assert(sizeof(int) <= sizeof(unsigned long long), "");

    bitset<24> data;

    operator int() const {
        return data.to_ulong() - (1 << 23);
    }

    fake_int24_t& operator=(int val) {
        assert(val >= -(1 << 23)); // 2's complement
        assert(val < (1 << 23));

        data = bitset<24>(val + (1 << 23));

        return *this;
    }
};

live demo

但是,

sizeof(fake_int24_t)并不一定是3,所以你可能想在那里加一个普通的整数。

答案 1 :(得分:1)

  

将24位整数编码到32位int的末尾。

OP的现有宏意味着24位无符号类型以小端存储 - 请参阅以下内容。
让我们假设24位 signed 使用相同的endian和常见的2&amp;补码整数编码。

SET_BYTE(DEST, START_BYTE_INDEX,   (uint8_t)(VALUE)); 
SET_BYTE(DEST, START_BYTE_INDEX+1, (uint8_t)(VALUE >> 8)); 
...

注意,我们不知道32位int的字节序,也不知道它的编码(2&#39; s,1&#39; s或sign-mag)。事实证明,我们不需要这些信息。

struct signed_24_bit {
  uint8_t other_data;
  uint8_t use_by_the_24_bit_int[3];
};

int decode_24_bit_integer(struct signed_24_bit x) {
  int32_t y = x.use_by_the_24_bit_int[0] // 1st byte of int24
      + (x.use_by_the_24_bit_int[1] * 0x100)
      + (x.use_by_the_24_bit_int[2] * 0x10000);

  // If y > INT24_MAX
  if (y > 0x7FFFFF) y -= 0x1000000;
  return y;
}

// Assume `x` is in range of `int24_t`
struct signed_24_bit encode_24_bit_integer(int x) {
  if ( x < 0) x += 0x1000000;
  struct signed_24_bit y = { 0, { x, x/0x100, x/0x10000 } };
  return y;
}

答案 2 :(得分:0)

我在24位部分使用符号幅度表示法:

int value = -22;
unsigned long target = std::abs(value) & ((1 << 23) - 1);
if (value < 0)
    target |= 1 << 23;

要提取值,只需颠倒过程:

int result = target & ((1 << 23) - 1);
if (target & (1 << 23))
    result = -result;

(警告:未经测试)