То, что вы пытались сделать, обладает элегантностью, которая не требует проверки порядка байтов для правильной работы. То, что вы пропустили, было некоторое смещение, чтобы указать значение в конечном значении:
int a = stuff[6] << 24 | stuff[7] << 16 | stuff[8] << 8 | stuff[9];
Одно это не заботится о порядке байтов, потому что с точки зрения языка оно основано на значениях, а не на байтах. Вы определяете, какие значения являются наиболее значимыми.
Тем не менее, это также предполагает 8-битный байт и как минимум 4-байтовый int. Если вы хотите элегантности использования, вы можете получить его с безопасной и общей абстракцией :
#include <array>
#include <climits>
#include <cstddef>
namespace detail {
// Could be replaced by an inline lambda-template in C++20.
template<typename T, std::size_t N, std::size_t... Is>
constexpr T pack_into_impl(const std::array<std::byte, N>& bytes, std::index_sequence<Is...>) {
// Build final value from right to left to make the math more clear
// and to use the least significant bytes available when N < sizeof(T).
// e.g., bytes[3] << 0 | bytes[2] << 8 | bytes[1] << 16 | bytes[0] << 24
return ((static_cast<int>(bytes[N-Is-1]) << (CHAR_BIT * Is)) | ...);
}
}
// Takes bytes to pack from most significant to least significant.
// N.B. this is not a production-ready doc comment for this function.
template<typename T, std::size_t N>
constexpr T pack_into(std::array<std::byte, N> bytes) {
static_assert(sizeof(T) >= N, "Destination type is too small for this many bytes");
return detail::pack_into_impl<T>(bytes, std::make_index_sequence<N>{});
}
// Convenience overload.
template<typename T, typename... Bytes>
constexpr T pack_into(Bytes... bytes) {
// Check that each Bytes type can be static_cast to std::byte.
// Maybe check that values fit within a byte.
return pack_into<T>(std::array{static_cast<std::byte>(bytes)...});
}
int main() {
static_assert(pack_into<int>(0x12, 0x34, 0x56, 0x78) == 0x12345678);
static_assert(pack_into<int>(0x01, 0x02) == 0x0102);
// pack_into<int>(0x01, 0x02, 0x03, 0x04, 0x05); // static_assert
}
Некоторое из этого можно очистить в C ++ 20 с помощью концепций и []<std::size_t... Is>
лямбда, но вы поймете эту идею. Естественно, вы также можете свободно трансформировать API, чтобы сделать размер неизвестным во время компиляции для удобства и использовать возможность проверки во время выполнения, когда передается слишком много байтов. Это зависит от вашего варианта использования.