【问题标题】:template constexpr endian converter (without UB)模板 constexpr 字节序转换器(无 UB)
【发布时间】:2021-03-09 13:14:37
【问题描述】:

我已经看到其他一些建议使用联合进行字节交换的答案(这是 UB 或无法在编译时完成)。

我已经写了我的,它有点工作,直到我遇到一些表明我的实现无效的案例。我找不到错误,你能帮帮我吗?

namespace impl
    {
                // ENDIAN is defined via CMake TestBigEndian
        constexpr bool native_is_big_endian()
        {
#ifdef ENDIAN
            return true;
#else
            return false;
#endif
        }
    }

    /*!
     * \brief std compliant type for endianness
     * \details
     * If all scalar types are little-endian, endian::native equals endian::little
     * If all scalar types are big-endian, endian::native equals endian::big
     */
    enum class endian
    {
        little,
        big,
        native = impl::native_is_big_endian() ? big : little
    };

    template<typename T>
    class swap_endian
    {
        constexpr static size_t sz_minus_one = sizeof(T) - 1;
        template<size_t> struct tag_s
        {
        };

        constexpr static T bitwise_or(tag_s<0>, T original, T res)
        {
            return res | (original >> sz_minus_one * 8);
        }

        template<size_t i>
        constexpr static T bitwise_or(tag_s<i>, T original, T res)
        {
            return bitwise_or(tag_s<i - 1>(), original, original << i * 8 >> sz_minus_one * 8 << i * 8);
        }

    public:
        constexpr static T swap(T u)
        {
            return bitwise_or(tag_s<sz_minus_one>(), u, 0);
        }
    };

    template<typename T>
    constexpr T swap_endian_v(T u)
    {
        return swap_endian<T>::swap(u);
    }

    template<endian From, typename T>
    constexpr T to_native_endian(T u)
    {
        return From == endian::native ? u : swap_endian_v(u);
    }

int main()
{
    static_assert(uint8_t(0xFA) == swap_endian_v(uint8_t(0xFA)), "Invalid result for endian swapping");
    static_assert(uint16_t(0x00AA) == swap_endian_v(uint16_t(0xAA00)), "Invalid result for endian swapping");
    static_assert(uint16_t(0xF0AA) == swap_endian_v(uint16_t(0xAAF0)), "Invalid result for endian swapping");
    static_assert(uint32_t(0x00'00'CC'00) == swap_endian_v(uint32_t(0x00'CC'00'00)),
                  "Invalid result for endian swapping");

// this fails
//    static_assert(uint32_t(0x6A'25'65'75) == swap_endian_v(uint32_t(0x75'65'25'6A)),
//                  "Invalid result for endian swapping");
    return 0;
}

请不要建议使用 BOOST。 在这一点上,我非常有兴趣找出我在算法中犯了什么样的错误。

【问题讨论】:

  • uint16_t(1) &gt;&gt; 8u 不会独立于当前架构的字节序评估为 0 吗?我认为在 C++20 的 std::endian 之前没有任何可移植的字节顺序编译时测试。
  • @DanielLangr 感谢您指出这一点!
  • swap_endian_v(uint32_t(0x75'65'25'6A)) 的输出是6575,这意味着高阶字节被丢弃
  • @Harry 我知道这一点。我在代码中看不到错误。
  • 我投票结束这个问题,因为它要求审查现有代码,而不是解决特定问题。

标签: c++ c++11 endianness constexpr


【解决方案1】:

您忽略了通过res 参数传递给bitwise_or 循环重载的第三个参数。如果

return bitwise_or(tag_s<i - 1>(), original,
  original << i * 8 >> sz_minus_one * 8 << i * 8);

改为:

return bitwise_or(tag_s<i - 1>(), original,
  res | original << i * 8 >> sz_minus_one * 8 << i * 8);

现场演示:https://godbolt.org/z/xW81z4

【讨论】:

    猜你喜欢
    • 2014-10-27
    • 1970-01-01
    • 2010-12-07
    • 2012-02-26
    • 1970-01-01
    • 2016-10-18
    • 2022-01-22
    • 1970-01-01
    • 2016-03-01
    相关资源
    最近更新 更多