Вы можете избежать разрезов с неявными преобразованиями:
uint32_t pack_helper(uint32_t c0, uint32_t c1, uint32_t c2, uint32_t c3) {
return c0 | (c1 << 8) | (c2 << 16) | (c3 << 24);
}
uint32_t pack(uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3) {
return pack_helper(c0, c1, c2, c3);
}
Идея заключается в том, что вы видите, а не «для каждого параметра, преобразовать его правильно, сдвиг«преобразовать все параметры правильно сдвиг и объединить их.» и объединить его ». Тем не менее, не так много.
Тогда:
template <int N>
uint8_t unpack_u(uint32_t packed) {
// cast to avoid potential warnings for implicit narrowing conversion
return static_cast<uint8_t>(packed >> (N*8));
}
template <int N>
int8_t unpack_s(uint32_t packed) {
uint8_t r = unpack_u<N>(packed);
return (r <= 127 ? r : r - 256); // thanks to caf
}
int main() {
uint32_t x = pack(4,5,6,-7);
std::cout << (int)unpack_u<0>(x) << "\n";
std::cout << (int)unpack_s<1>(x) << "\n";
std::cout << (int)unpack_u<3>(x) << "\n";
std::cout << (int)unpack_s<3>(x) << "\n";
}
Выход:
4
5
249
-7
Это, как портативные, как типы uint32_t
, uint8_t
и int8_t
. Ни один из них не требуется на C99, а заголовок stdint.h не определен в C++ или C89. Если типы существуют и соответствуют требованиям C99, код будет работать. Конечно, в C для функций распаковки вместо параметра шаблона потребуется параметр функции. Вы также можете предпочесть на C++, если хотите писать короткие петли для распаковки.
Чтобы устранить тот факт, что типы являются необязательными, вы можете использовать uint_least32_t
, что требуется на C99. Аналогично uint_least8_t
и int_least8_t
. Вы должны изменить код pack_helper и unpack_u:
uint_least32_t mask(uint_least32_t x) { return x & 0xFF; }
uint_least32_t pack_helper(uint_least32_t c0, uint_least32_t c1, uint_least32_t c2, uint_least32_t c3) {
return mask(c0) | (mask(c1) << 8) | (mask(c2) << 16) | (mask(c3) << 24);
}
template <int N>
uint_least8_t unpack_u(uint_least32_t packed) {
// cast to avoid potential warnings for implicit narrowing conversion
return static_cast<uint_least8_t>(mask(packed >> (N*8)));
}
Чтобы быть честным, то это вряд ли стоит - скорее всего, остальная часть приложения написана на предположении, что int8_t
и т.д. действительно существуют. Это редкая реализация, которая не имеет 8-битного и 32-битного 2-го уровня.
В C и C++ символ 'char' _always_ имеет размер одного байта. Байт _may_ не должен быть восьми бит. –
+1: для разбивки на две функции и использование функции вместо макроса. Это идеальный случай наличия встроенной функции. – Arun
Мне любопытно, почему вы включаете одну функцию C++ (встроенные функции), но осуждаете другую (улучшенные операторы трансляции) ... Стили C-Style устарели по какой-то причине. Иначе +1. –