0

So I know how to detect endianness programmatically.

Question

Is there more standard or native (closed box) way of detecting endianness? does WINAPI offer such solution?

Community
  • 1
  • 1
idanshmu
  • 5,061
  • 6
  • 46
  • 92
  • 1
    standard way is to use `ntohl()` and `htonl()` when converting data, they "know" what endianness the machine has – bobah Oct 23 '14 at 13:00
  • Correct me if I'm wrong, but AFAIK all architectures Windows runs on are little endian anyway. – Jabberwocky Oct 23 '14 at 13:18
  • 1
    @Michael: ARM CPUs can boot into both big endian and little endian mode, although - as far as I know - all Windows systems running on ARM CPUs do boot into little endian mode. However, I cannot make a statement about future Windows releases running on not yet known hardware. As such the question is valid. – IInspectable Oct 23 '14 at 13:31

1 Answers1

3

There is no standard C++ provided functionality for detecting endian. Both myself, and Beman Dawes are working to correct that. However success in such an endeavor is both glacially slow and far from assured.

I have been experimenting with the following header:

https://github.com/HowardHinnant/hash_append/blob/master/endian.h

which as shown is not portable to Windows, but certainly could be easily ported to Windows by a std::lib implementor. The mechanism is very simplistic:

// endian provides answers to the following questions:
// 1.  Is this system big or little endian?
// 2.  Is the "desired endian" of some class or function the same as the
//     native endian?
enum class endian
{
    native = // unspecified,
    little = // unspecified,
    big    = // unspecified
};

If you are on a little endian machine, then endian::native == endian::little.

If you are on a big endian machine, then endian::native == endian::big.

If you are on a mixed endian machine (I haven't seen one in a long while), then endian::native has a value other than big or little.

This file:

https://github.com/HowardHinnant/hash_append/blob/master/hash_append.h

shows some example uses of this facility. For example there is something called a Hasher that can request that scalars supplied to it come in one of three forms:

  1. native endian, whatever that happens to be.
  2. big endian.
  3. little endian.

And there is a little utility that will reverse (or not) the bytes of the scalar, depending on the wishes of the Hasher, and the native endian of the platform:

template <class T>
constexpr
inline
void
reverse_bytes(T& t)
{
    unsigned char* bytes = static_cast<unsigned char*>(std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
    for (unsigned i = 0; i < sizeof(T)/2; ++i)
        std::swap(bytes[i], bytes[sizeof(T)-1-i]);
}

template <class T>
constexpr
inline
void
maybe_reverse_bytes(T& t, std::true_type)
{
}

template <class T>
constexpr
inline
void
maybe_reverse_bytes(T& t, std::false_type)
{
    reverse_bytes(t);
}

template <class T, class Hasher>
constexpr
inline
void
maybe_reverse_bytes(T& t, Hasher&)
{
    maybe_reverse_bytes(t, std::integral_constant<bool,
                                           Hasher::endian == endian::native>{});
}
Howard Hinnant
  • 206,506
  • 52
  • 449
  • 577
  • 1
    Okay, this is awesome. But the question is asking what tools the Windows API provides. – Lightness Races in Orbit Oct 23 '14 at 17:14
  • I have no answer for that part of the OP's question. I only answered the part of his question that I could. I welcome other answers that provide that addition information. – Howard Hinnant Oct 23 '14 at 19:51
  • I used to wonder why it was so hard for compilers to just offer a portable, static method of getting a target's endianness. Turns out hardware with dynamic endianness is more common than you might think, even if the dynamic capabilities are rarely used. – bames53 Oct 23 '14 at 20:51
  • We need an API that supports both static and dynamic endianness. If a target has static endianness then the various swap calls should be statically known and optimized. If endianness is dynamic then the API should hide the runtime check and do whatever the right thing is in terms of setting the behavior of the swap functions. Maybe this can be supported by a function that is `constexpr` for platforms with static endianness, and non-`constexpr` otherwise? – bames53 Oct 23 '14 at 20:52
  • @bames53: I know that some hardware (e.g. ARM) can be switched between big and little endian. However, are you aware of any *platform* for which this is true? I.e. something you can compile a C++ program for, run it, and have the endian change at run time? I have a hard time imagining how one could build an OS to run in such an environment. However if you're aware of one, then I stand corrected. – Howard Hinnant Oct 23 '14 at 21:29
  • PPC allows it according to [this](http://en.wikipedia.org/wiki/PowerPC#Endian_modes). [This](http://stackoverflow.com/a/22355194/365496) seems to indicate that ARM can have an endianness fixed in hardware, or the hardware can be set to allow software to set endianness. – bames53 Oct 23 '14 at 23:25
  • But can you target a C++11 (or better) compiler (possibly in freestanding configuration) to one of these hardware/OS combinations to generate a C++ program that will experience more than one endian during program execution? I'm not so concerned about a theoretical possibility in a university computer lab. I'm concerned that the C++ standard isn't driven by a purely theoretical platform that will never exist in practice. – Howard Hinnant Oct 23 '14 at 23:36
  • 1
    On PPC the instruction to access the machine state register is privileged so setting it requires a kernel extension. I believe this is the way VirtualPC [operated](http://en.wikipedia.org/wiki/PowerPC#Design_features). Certainly I can compile C++ code that attempts to use the MSR, but in user-mode it produces `EXC_BAD_INSTRUCTION`. Maybe I'll give writing a kernel extension a shot and see what happens... – bames53 Oct 24 '14 at 00:47
  • @bames53: Thanks much for your careful examination. – Howard Hinnant Oct 24 '14 at 02:37