constexpr and endianness

后端 未结 8 468
無奈伤痛
無奈伤痛 2020-12-24 12:42

A common question that comes up from time to time in the world of C++ programming is compile-time determination of endianness. Usually this is done with barely portable #if

相关标签:
8条回答
  • 2020-12-24 12:47

    My first post. Just wanted to share some code that I'm using.

    //Some handy defines magic, thanks overflow
    #define IS_LITTLE_ENDIAN  ('ABCD'==0x41424344UL) //41 42 43 44 = 'ABCD' hex ASCII code
    #define IS_BIG_ENDIAN     ('ABCD'==0x44434241UL) //44 43 42 41 = 'DCBA' hex ASCII code
    #define IS_UNKNOWN_ENDIAN (IS_LITTLE_ENDIAN == IS_BIG_ENDIAN)
    
    //Next in code...
    struct Quad
    {
        union
        {
    #if IS_LITTLE_ENDIAN
            struct { std::uint8_t b0, b1, b2, b3; };
    
    #elif IS_BIG_ENDIAN
            struct { std::uint8_t b3, b2, b1, b0; };
    
    #elif IS_UNKNOWN_ENDIAN
    #error "Endianness not implemented!"
    #endif
    
            std::uint32_t dword;
        };
    };
    

    Constexpr version:

    namespace Endian
    {
        namespace Impl //Private
        {
            //41 42 43 44 = 'ABCD' hex ASCII code
            static constexpr std::uint32_t LITTLE_{ 0x41424344u };
    
            //44 43 42 41 = 'DCBA' hex ASCII code
            static constexpr std::uint32_t BIG_{ 0x44434241u };
    
            //Converts chars to uint32 on current platform
            static constexpr std::uint32_t NATIVE_{ 'ABCD' };
        }
    
    
    
        //Public
        enum class Type : size_t { UNKNOWN, LITTLE, BIG };
    
        //Compare
        static constexpr bool IS_LITTLE   = Impl::NATIVE_ == Impl::LITTLE_;
        static constexpr bool IS_BIG      = Impl::NATIVE_ == Impl::BIG_;
        static constexpr bool IS_UNKNOWN  = IS_LITTLE == IS_BIG;
    
        //Endian type on current platform
        static constexpr Type NATIVE_TYPE = IS_LITTLE ? Type::LITTLE : IS_BIG ? Type::BIG : Type::UNKNOWN;
    
    
    
        //Uncomment for test. 
        //static_assert(!IS_LITTLE, "This platform has little endian.");
        //static_assert(!IS_BIG_ENDIAN, "This platform has big endian.");
        //static_assert(!IS_UNKNOWN, "Error: Unsupported endian!");
    }
    
    0 讨论(0)
  • 2020-12-24 12:49

    This may seem like cheating, but you can always include endian.h... BYTE_ORDER == BIG_ENDIAN is a valid constexpr...

    0 讨论(0)
  • 2020-12-24 12:50

    If your goal is to insure that the compiler optimizes little_endian() into a constant true or false at compile-time, without any of its contents winding up in the executable or being executed at runtime, and only generating code from the "correct" one of your two Foo templates, I fear you're in for a disappointment.

    I also am not a language lawyer, but it looks to me like constexpr is like inline or register: a keyword that alerts the compiler writer to the presence of a potential optimization. Then it's up to the compiler writer whether or not to take advantage of that. Language specs typically mandate behaviors, not optimizations.

    Also, have you actually tried this on a variety of C++0x complaint compilers to see what happens? I would guess most of them would choke on your dual templates, since they won't be able to figure out which one to use if invoked with false.

    0 讨论(0)
  • 2020-12-24 12:55

    I was able to write this:

    #include <cstdint>
    
    class Endian
    {
    private:
        static constexpr uint32_t uint32_ = 0x01020304;
        static constexpr uint8_t magic_ = (const uint8_t&)uint32_;
    public:
        static constexpr bool little = magic_ == 0x04;
        static constexpr bool middle = magic_ == 0x02;
        static constexpr bool big = magic_ == 0x01;
        static_assert(little || middle || big, "Cannot determine endianness!");
    private:
        Endian() = delete;
    };
    

    I've tested it with g++ and it compiles without warnings. It gives a correct result on x64. If you have any big-endian or middle-endian proccesor, please, confirm that this works for you in a comment.

    0 讨论(0)
  • 2020-12-24 12:58

    That is a very interesting question.

    I am not Language Lawyer, but you might be able to replace the reinterpret_cast with a union.

    const union {
        int int_value;
        char char_value[4];
    } Endian = { 0xAABBCCDD };
    
    constexpr bool little_endian()
    {
       return Endian[0] == 0xDD;
    }
    
    0 讨论(0)
  • 2020-12-24 12:59

    There is std::endian in the upcoming C++20.

    #include <type_traits>
    
    constexpr bool little_endian() noexcept
    {
        return std::endian::native == std::endian::little;
    }
    
    0 讨论(0)
提交回复
热议问题