HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

Checking endianness at compile-time

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
compilecheckingtimeendianness

Problem

I've tried to make a portable way of ensuring endian-specific code gets generated at compile time using C++11, however I only have a computer with Windows on it to test at the moment. Because of this, I'm a bit limited in the amount of places where I can test my code. Also, would anyone be able to offer some best-practices or tips different ways to improve this? My intention is to use this in a small math library where serialization is a pretty high priority.

The function itself is fairly simple. It checks the values of an array for whichever byte comes first. It then returns a constant value, representing the target machine's endianness, through an enumeration. If everything works correctly, then this code can replace any runtime checks that either I or anyone else uses for endian checking.

```
/*
* A simple compile-time endian test
* g++ -std=c++11 -Wall -Werror -Wextra -pedantic -pedantic-errors endian.cpp -o endian
*
* This can be used with specialized template functions, classes, and class
* methods in order better tailor code and reduce reliance on runtime
* checking systems.
*/

#include
#include

/**
* hl_endianness
*
* This enumeration can be placed into templated objects in order to generate
* compile-time code based on a program's target endianness.
*
* The values placed in this enum are used just in case the need arises in
* order to manually compare them against the number order in the
* endianValues[] array.
*/
enum hl_endianness : uint32_t {
HL_LITTLE_ENDIAN = 0x03020100,
HL_BIG_ENDIAN = 0x00010203,
HL_PDP_ENDIAN = 0x01000302,
HL_UNKNOWN_ENDIAN = 0xFFFFFFFF
};

/**
* A constant array used to determine a program's target endianness. The
* values
* in this array can be compared against the values placed in the
* hl_endianness enumeration.
*/
static constexpr uint8_t endianValues[4] = {0, 1, 2, 3};

/**
* A simple function that can be used to help determine a program's endianness
* at compile-time

Solution

Just a couple points:

-
Endian-ness is not generally based on the Operating System but on the processor. For example, Intel x86 processors are little-endian regardless of it running Windows or Linux.

-
Your code will always return HL_LITTLE_ENDIAN. Why? Because if

static constexpr uint8_t endianValues[4] = {0, 1, 2, 3};


then endianValues[0] == 0 will always be true! Suppose you had

char x[4] = {'c','o','d', 'e'};


Don't you think it would be shocking if x[0] == 'e' instead of x[0] == 'c'?

The standard way is to use a union. Something like this:

union endian_tester {
    uint32_t   n;
    uint8_t    p[4];
};

const endian_tester sample = {0x01020304}; // this initializes .n

constexpr hl_endianness getEndianOrder() {
    return
        (0x04 == sample.p[0])               // If Little Endian Byte Order,
            ? HL_LITTLE_ENDIAN              
            : (0x01 == sample.p[0])         // Else if Big Endian Byte Order,
                ? HL_BIG_ENDIAN             
                : (0x02 == sample.p[0])     // Else if PDP Endian Byte Order,
                       ...(etc)...


Be aware that constexpr isn't fully supported in my version of Visual Studio 2013 Express.

-
Not clear to me why you need to use fancy values for HL_LITTLE_ENDIAN, HL_BIG_ENDIAN, etc. You can use 1, 2, etc instead of 0x03020100, 0x00010203, etc.

-
A related question answered on Stack Overflow (Detecting endianness programmatically in a C++ program)

Code Snippets

static constexpr uint8_t endianValues[4] = {0, 1, 2, 3};
char x[4] = {'c','o','d', 'e'};
union endian_tester {
    uint32_t   n;
    uint8_t    p[4];
};

const endian_tester sample = {0x01020304}; // this initializes .n

constexpr hl_endianness getEndianOrder() {
    return
        (0x04 == sample.p[0])               // If Little Endian Byte Order,
            ? HL_LITTLE_ENDIAN              
            : (0x01 == sample.p[0])         // Else if Big Endian Byte Order,
                ? HL_BIG_ENDIAN             
                : (0x02 == sample.p[0])     // Else if PDP Endian Byte Order,
                       ...(etc)...

Context

StackExchange Code Review Q#45675, answer score: 4

Revisions (0)

No revisions yet.