constexptr to calculate something at compiletime

Hi

I looked up a way to check the endianness of the system and found this snippet of code:
1
2
3
4
5
6
7
8
9
bool is_big_endian()
{
    union {
        uint32_t i;
        char c[4];
    } bint = {0x01020304};

    return bint.c[0] == 1; 
}


and i was just wondering, because im new to the concept of constexptr and inline:
if i change the code to
1
2
3
4
5
6
7
8
9
10
inline bool is_big_endian()
{
    union {
        uint32_t i;
        char c[4];
    } bint = {0x01020304};
    constexpr bool check = (bint.c[0] == 1);

    return check; 
}


Will it then calculate the endianness at compile time? instead of runtime ?

(also, is my usage of inline correct? )
Last edited on
Will it then calculate the endianness at compile time? instead of runtime ?

Neither, because that doesn't seem to compile. bint isn't constexpr, so try not making it an anonymous union.

But even when I change it to
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>

inline constexpr bool is_big_endian()
{
    union Foo {
        uint32_t i;
        char c[4];
    };
    
    constexpr Foo bint = {0x01020304};
    constexpr bool check = (bint.c[0] == 1);

    return check; 
}

int main() {
	
    is_big_endian();
    return 0;
}

It still doesn't compile.
1
2
3
4
prog.cpp: In function ‘constexpr bool is_big_endian()’:
prog.cpp:11:43: error: accessing ‘is_big_endian()::Foo::c’ member instead of initialized ‘is_big_endian()::Foo::i’ member in constant expression
     constexpr bool check = (bint.c[0] == 1);
                                           ^


I'm not a standard expert, but in modern C++ I believe "type punning" is undefined behavior (i.e., setting i to be a number, and then getting the first byte of that number through the union), although may still "work" in practice.
https://stackoverflow.com/questions/11373203/accessing-inactive-union-member-and-undefined-behavior/11996970#11996970

There's a bunch of different things you can try, but I don't think any of them are 100% portable.
https://stackoverflow.com/questions/4239993/determining-endianness-at-compile-time
https://gcc.gnu.org/ml/gcc-help/2007-07/msg00342.html

Also, inline these days just means "allow more than one definition of this function", it won't affect it being compile-time or not.

Your is_big_endian function itself is not constexpr. Is this intentional?

_________________________________________

The biggest picture:

What's so bad about it being run-time? It would only need to be calculated once... and then you can put the bool inside a static object to be referenced for the remainder of the program. You wouldn't not notice any difference even if your is_big_endian function did compile.

The only way to actually get rid of complete segments of code at compile time would be with macros "#if ... " which would be different per compiler.

This will compile but it's run-time.
1
2
3
4
5
6
7
8
9
10
11
12
13

inline bool is_big_endian()
{
    union Foo {
        uint32_t i;
        char c[4];
    };
    
    constexpr Foo bint = {0x01020304};
    bool check = (bint.c[0] == 1);

    return check; 
}
Last edited on
Topic archived. No new replies allowed.