двоичный файл — C ++, упаковывающий разные типы данных в одну длинную переменную

Я попал в ловушку, пытаясь упаковать пару переменных в одну переменную длиной 8 байт.

По сути, у меня есть пара коротких предметов, которые имеют небольшой двоичный размер, и мне нужно собрать их вместе, чтобы отправить в класс, который должен быть в состоянии распаковать его обратно.

Итак, я сделал следующее:

typedef unsigned long long PACKAGE; // 8 byte (shows as _int64 in debug)
(sizeof returns '8')
unsigned int dat1   = 25;  // 1 byte long max
unsigned int dat2   = 1;   // 4 bit long max
unsigned int dat3   = 100; // 2 byte long max
unsigned int dat4   = 200; // 4 byte long max
unsigned int dat5   = 2;   // 4 bit long max

Затем я делаю переменную типа PACKAGE, которая пуста (0)

PACKAGE pack = 0;

И я хочу бросить переменные в этот пакет с помощью бинарных операций, я делаю:

pack = (dat1 << 56) | (dat2 << 52) | (dat3 << 36) | (dat4 << 4) | dat5;

это работает только наполовину хорошо, я рассчитал, что я должен получить десятичное значение пакета равным 2526526262902525058, или же

0010001100010000000001100100000000000000000000000000110010000010

как бинарный, однако я получаю 588254914, или же
00100011000100000000111011000010‬ как бинарный
что-то правильное в его хвосте и голове, но средняя часть где-то отсутствует.

И когда это будет сделано, я все еще собираюсь как-то извлечь данные обратно.

1

Решение

Я бы предпочел использовать битовое структура для представления такого типа (также используйте uint64_t быть уверенным в доступном размере):

union PACKAGE {
struct bits {
uint64_t dat1 : 8;  // 1 byte long max
uint64_t dat2 : 4;  // 4 bit long max
uint64_t dat3 : 16; // 2 byte long max
uint64_t dat4 : 32; // 4 byte long max
uint64_t dat5 : 4;  // 4 bit long max
};
uint64_t whole; // for convenience
};

Как уже упоминалось в Комментарии Вы могли бы даже использовать uint_least64_t тип данных, чтобы убедиться, что ваша цель поддерживает его (так как наличие uint64_t является необязательным из текущего стандарта c ++):

union PACKAGE {
struct bits {
uint_least64_t dat1 : 8;  // 1 byte long max
uint_least64_t dat2 : 4;  // 4 bit long max
uint_least64_t dat3 : 16; // 2 byte long max
uint_least64_t dat4 : 32; // 4 byte long max
uint_least64_t dat5 : 4;  // 4 bit long max
};
uint_least64_t whole; // for convenience
};
2

Другие решения

При условии, что sizeof(unsigned int) != sizeof(unsigned long long)левый операнд каждого сдвига имеет неправильный тип. Каждая операция сдвига усекается (возможно, до 32 бит).

Попробуйте, например:

typedef unsigned long long PACKAGE; // 8 byte (shows as _int64 in debug)
(sizeof returns '8')
unsigned long long dat1   = 25;  // 1 byte long max
unsigned long long dat2   = 1;   // 4 bit long max
unsigned long long dat3   = 100; // 2 byte long max
unsigned long long dat4   = 200; // 4 byte long max
unsigned long long dat5   = 2;   // 4 bit long max

pack = (dat1 << 56) | (dat2 << 52) | (dat3 << 36) | (dat4 << 4) | dat5;

или же:

typedef unsigned long long PACKAGE; // 8 byte (shows as _int64 in debug)
(sizeof returns '8')
unsigned int dat1   = 25;  // 1 byte long max
unsigned int dat2   = 1;   // 4 bit long max
unsigned int dat3   = 100; // 2 byte long max
unsigned int dat4   = 200; // 4 byte long max
unsigned int dat5   = 2;   // 4 bit long max

pack = ((PACKAGE)dat1 << 56) | ((PACKAGE)dat2 << 52) | ((PACKAGE)dat3 << 36) | ((PACKAGE)dat4 << 4) | (PACKAGE)dat5;

Примечание: Хорошо, в действительности каждая операция сдвига, в которой правый операнд больше, чем размер левого типа, в битах вызывает неопределенное поведение. Типичным неопределенным поведением является усечение, но стандарт допускает любое другое поведение, вплоть до глобальной термоядерной войны.

1

По вопросам рекламы [email protected]