C - три байта в один со знаком int
У меня есть датчик, который дает свой выход в три байта. Я читаю это так:
unsigned char byte0,byte1,byte2;
byte0=readRegister(0x25);
byte1=readRegister(0x26);
byte2=readRegister(0x27);
Теперь я хочу, чтобы эти три байта были объединены в одно число:
int value;
value=byte0 + (byte1 << 8) + (byte2 << 16);
это дает мне значения от 0 до 16,777,215, но я ожидаю значения от -8,388,608 до 8,388,607. Я думал что int
был уже подписан его реализацией. Даже если я попытаюсь определить это как signed int value;
это все еще дает мне только положительные числа. Итак, я думаю, мой вопрос, как преобразовать int в дополнение к двум?
Спасибо!
2 ответа
То, что вам нужно выполнить, называется расширением знака. У вас есть 24 значащих бита, но вы хотите 32 значащих бита (обратите внимание, что вы предполагаете int
быть 32-битным, что не всегда верно; вам лучше использовать тип int32_t
определяется в stdint.h
). Пропущенные 8 старших битов должны быть либо всеми нулями для положительных значений, либо всеми единицами для отрицательных. Он определяется старшим значащим битом 24-битного значения.
int32_t value;
uint8_t extension = byte2 & 0x80 ? 0xff:00; /* checks bit 7 */
value = (int32_t)byte0 | ((int32_t)byte1 << 8) | ((int32_t)byte2 << 16) | ((int32_t)extension << 24);
РЕДАКТИРОВАТЬ: Обратите внимание, что вы не можете сдвинуть 8-битное значение на 8 или более бит, это неопределенное поведение. Сначала вам придется привести его к более широкому типу.
#include <stdint.h>
uint8_t byte0,byte1,byte2;
int32_t answer;
// assuming reg 0x25 is the signed MSB of the number
// but you need to read unsigned for some reason
byte0=readRegister(0x25);
byte1=readRegister(0x26);
byte2=readRegister(0x27);
// so the trick is you need to get the byte to sign extend to 32 bits
// so force it signed then cast it up
answer = (int32_t)((int8_t)byte0); // this should sign extend the number
answer <<= 8;
answer |= (int32_t)byte1; // this should just make 8 bit field, not extended
answer <<= 8;
answer |= (int32_t)byte2;
Это также должно работать
answer = (((int32_t)((int8_t)byte0))<<16) + (((int32_t)byte1)<< 8) + byte2;
Я могу быть слишком агрессивен с круглыми скобками, но я никогда не доверяю себе операторам смещения:)