将 std::array<char, 10> 的最后一个字符转换为 int

Convert last characters of std::array<char, 10> to int

给定以下数组:std::array<char, 10> stuff我想将最后 4 个字符转换为相应的 int32 值。

我尝试对最后一项进行 OR 操作链接,但似乎不是正确的方法:

int a = int(stuff[6] | stuff[7] | stuff[8] | stuff[9])

有什么优雅的方法可以解决这个问题吗?

信不信由你,尽管这是 C++,memcpy() 是做这种事情的推荐方法:

int32_t a;
memcpy(&a, stuff.data() + 6, 4);

它避免了严格的别名冲突,编译器将优化 memcpy 调用。

如果您加载的数据是在具有不同 CPU 体系结构的不同计算机上创建的,请注意字节顺序差异。

您尝试做的事情很优雅,不需要字节序检查就可以正常工作。您错过的是一些转变以表明最终值的重要性:

int a = stuff[6] << 24 | stuff[7] << 16 | stuff[8] << 8 | stuff[9];

这本身并不关心字节序,因为从语言的角度来看,它是基于值而不是字节。您确定哪些值最重要。

也就是说,这还假设一个 8 位字节和至少 4 字节的 int。如果你想要优雅的使用,你可以用 safe and general abstraction:

#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> lambda 来清理,但你明白了。当然,为了方便起见,您也可以随意转换 API 以在编译时使大小未知,并在给定的字节过多时进行可能的运行时检查。这取决于您的用例。