您可以避免使用隐式转换进行强制转换:
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
etc 确实存在的情况下编写的。这是一种没有 8 位和 32 位 2 的补码类型的罕见实现。