我需要将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
我假设我只需要用签名值完全避免这些转变,但我不确定正确的方法是什么?
答案 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;
}
};
但是, 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;
(警告:未经测试)