Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Is there a way to determine endianess in a constexpr-function ?

176 views
Skip to first unread message

Bonita Montero

unread,
Jan 1, 2020, 11:46:45 AM1/1/20
to
Is there a way to determine endianess in a constexpr-function
which might return true for little endian and false for big
endian? I guess not, but maybe I din't consider a trick here.

Bo Persson

unread,
Jan 1, 2020, 12:49:16 PM1/1/20
to
"Not" is probably the correct answer here, so in C++20 we get
std::endian where the implementation provides the info.

https://en.cppreference.com/w/cpp/types/endian


Bo Persson

Bonita Montero

unread,
Jan 1, 2020, 12:54:57 PM1/1/20
to
>> Is there a way to determine endianess in a constexpr-function
>> which might return true for little endian and false for big
>> endian? I guess not, but maybe I din't consider a trick here.

> "Not" is probably the correct answer here, so in C++20 we get
> std::endian where the implementation provides the info.
> https://en.cppreference.com/w/cpp/types/endian

Where's the support for the DEC PDP-11 and Honeywell 316 endianess???
;-)

David Brown

unread,
Jan 1, 2020, 5:21:32 PM1/1/20
to
Gone - along with ones' complement integers.

If your code is limited to a known set of compilers or platforms, most
have predefined macros that give you the endianness. There are some
header files floating around the web that have checks for a large number
of different toolchains if you don't want to read all the documentation
yourself.

Robert Wessel

unread,
Jan 1, 2020, 7:25:47 PM1/1/20
to
On Wed, 1 Jan 2020 23:21:23 +0100, David Brown
<david...@hesbynett.no> wrote:

>On 01/01/2020 18:54, Bonita Montero wrote:
>>>> Is there a way to determine endianess in a constexpr-function
>>>> which might return true for little endian and false for big
>>>> endian? I guess not, but maybe I din't consider a trick here.
>>
>>> "Not" is probably the correct answer here, so in C++20 we get
>>> std::endian where the implementation provides the info.
>>> https://en.cppreference.com/w/cpp/types/endian
>>
>> Where's the support for the DEC PDP-11 and Honeywell 316 endianess???
>> ;-)
>>
>
>Gone - along with ones' complement integers.


Are byte orders other than the two major ones actually disallowed now
(or at least in C++20)? The enum provides at least a small loophole
for non-big, non-little endian implorations.

Ben Bacarisse

unread,
Jan 1, 2020, 7:47:52 PM1/1/20
to
David Brown <david...@hesbynett.no> writes:

> On 01/01/2020 18:54, Bonita Montero wrote:
>>>> Is there a way to determine endianess in a constexpr-function
>>>> which might return true for little endian and false for big
>>>> endian? I guess not, but maybe I din't consider a trick here.
>>
>>> "Not" is probably the correct answer here, so in C++20 we get
>>> std::endian where the implementation provides the info.
>>> https://en.cppreference.com/w/cpp/types/endian
>>
>> Where's the support for the DEC PDP-11 and Honeywell 316 endianess???
>> ;-)
>>
>
> Gone - along with ones' complement integers.

Not entirely! An implementation must signal a non-uniform endianness,
but it can't, using std::endian alone, say much more about it.

--
Ben.

Pavel

unread,
Jan 2, 2020, 10:29:08 PM1/2/20
to
Why not, it's actually not difficult.

Below is a simple example (actually returns true for big endian) but I think
more complex checks can be built upon same principle.

#include <cstdint>
#include <iostream>
using namespace std;

enum ProbeEnum : int16_t { ProbeValue = 0x0100 };
constexpr union {
ProbeEnum p;
char ca[2];
} ProbeVal{ProbeValue};

constexpr
bool
IsBigEndian()
{
return !!ProbeVal.ca[0];
}

int
main(int, char*[])
{
cout << "IsBigEndian=" << IsBigEndian() << endl;


return 0;
}

HTH
-Pavel

Siri Cruise

unread,
Jan 2, 2020, 10:51:41 PM1/2/20
to
In article <1yyPF.127450$QU2....@fx01.iad>,
Pavel <pauldont...@removeyourself.dontspam.yahoo> wrote:

> Below is a simple example (actually returns true for big endian) but I think
> more complex checks can be built upon same principle.

Four bytes let's you detect Dec's middle endian.

--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
The first law of discordiamism: The more energy This post / \
to make order is nore energy made into entropy. insults Islam. Mohammed

Öö Tiib

unread,
Jan 3, 2020, 2:14:18 AM1/3/20
to
In C++ type punning through union is undefined behavior. Type punning
through reinterpret cast to pointer of bytes and type punning through
memcpy are valid but are not constexpr in C++. So I feel that your code
has undefined behavior.

Bonita Montero

unread,
Jan 3, 2020, 2:31:25 AM1/3/20
to
IsBigEndian isn't guaranteed compile-time evaluated.

Bonita Montero

unread,
Jan 3, 2020, 2:43:38 AM1/3/20
to
if i do: "if constexpr( IsBigEndian() )" I'll get:
"error C2131: expression did not evaluate to a constant"

Pavel

unread,
Jan 5, 2020, 12:52:04 AM1/5/20
to
Right. If I try to do

constexpr bool ibe = IsBigEndian();

I receive more explicit error message from gcc:

error: accessing ‘Endian::ca’ member instead of initialized ‘Endian::p’ member
in constant expression

So the Big Brother is watching.. Then the answer to your question is probably
"not possible until C++20". With C++20 you should be able to write a similar
code using bit_cast which is constexpr as mentioned by Bo Persson on another thread.

Bonita Montero

unread,
Jan 5, 2020, 1:43:48 AM1/5/20
to
> So the Big Brother is watching.. Then the answer to your question is
> probably "not possible until C++20". With C++20 you should be able to
> write a similar code using bit_cast which is constexpr as mentioned by
> Bo Persson on another thread.

C++20 should not only provide an enum which tells if the machine is big
or little endian. It should also provide wrapper-classes of all basic
integral and floating-point datatypes in big as well as little endian
with overloaded operators that swap the bytes if appropriate on reading
and assignment. This could be f.e. done internally by the standard
library's specific intrinsics for byte-swapping (f.e. with BSWAP
for x86).

Bonita Montero

unread,
Jan 5, 2020, 2:31:24 AM1/5/20
to
So something like this:

#if defined(_MSC_VER)
#include <intrin.h>
#endif
#include <cstdint>

template<typename T>
struct big_endian
{
T operator =( T value );
operator T();
private:
big_endian();
};

template<>
struct big_endian<std::uint32_t>
{
big_endian() = default;
big_endian( std::uint32_t value );
std::uint32_t operator =( std::uint32_t value );
operator std::uint32_t();
private:
std::uint32_t swap( std::uint32_t value );
std::uint32_t m_value;
};

inline
big_endian<std::uint32_t>::big_endian( std::uint32_t value )
{
m_value = swap( value );
}

inline
std::uint32_t big_endian<std::uint32_t>::operator =( std::uint32_t value )
{
m_value = swap( value );
return value;
}

inline
big_endian<std::uint32_t>::operator std::uint32_t()
{
return swap( m_value );
}

inline
std::uint32_t big_endian<std::uint32_t>::swap( std::uint32_t value )
{
#if defined(_MSC_VER)
return _byteswap_ulong( value );
#elif defined(__GNUC__)
return __builtin_bswap32( value );
#else
std::uint32_t swapA = (value & 0x0000FFFFu) << 16,
swapB = (value & 0xFFFF0000u) >> 16;
return (swapA & 0x00FF00FFu) << 8 | (swapA & 0xFF00FF00u) >> 8;
#endif
}

Bonita Montero

unread,
Jan 5, 2020, 2:34:26 AM1/5/20
to
>     std::uint32_t swapA = (value & 0x0000FFFFu) << 16,
>              swapB = (value & 0xFFFF0000u) >> 16;
>     return (swapA & 0x00FF00FFu) << 8 | (swapA & 0xFF00FF00u) >> 8;

Forget it, doesn't work, but care about the principle.

Bonita Montero

unread,
Jan 5, 2020, 2:38:31 AM1/5/20
to
>     std::uint32_t swapA = (value & 0x0000FFFFu) << 16,
>              swapB = (value & 0xFFFF0000u) >> 16;
>     return (swapA & 0x00FF00FFu) << 8 | (swapA & 0xFF00FF00u) >> 8;

This is correct:
std::uint32_t swapA = (value & 0x0000FFFFu) << 16 | (value &
0xFFFF0000u) >> 16;
return (swapA & 0x00FF00FFu) << 8 | (swapB & 0xFF00FF00u) >> 8;

0 new messages