Reputation:
Ugh, endianness. The problem is the memory layout of say, 0x65736c6166
will be different on different endians. This is because the number is being defined by value. The 66
on the end of my constant will go in the first byte on little endian systems, and on the last byte on big endian systems, yet the number is the same. How can I define number variables by memory layout rather than by value, so on different endians, their memory layout will stay the same, but their value will be completely different? And it needs to be considered compile-time constant.
Upvotes: 1
Views: 135
Reputation: 141030
How can I define number variables by memory layout rather than by value, so on different endians, their memory layout will stay the same, but their value will be completely different?
Well, there are only two endianess to handle. You could write a macro function that would convert host byte order to the endianess you want and just use such macro when using the constant.
#include <assert.h>
#include <string.h>
#include <inttypes.h>
// Copied from glibc bits/byteswap.h
#define bswap_constant_64(x) \
((((x) & 0xff00000000000000ull) >> 56) \
| (((x) & 0x00ff000000000000ull) >> 40) \
| (((x) & 0x0000ff0000000000ull) >> 24) \
| (((x) & 0x000000ff00000000ull) >> 8) \
| (((x) & 0x00000000ff000000ull) << 8) \
| (((x) & 0x0000000000ff0000ull) << 24) \
| (((x) & 0x000000000000ff00ull) << 40) \
| (((x) & 0x00000000000000ffull) << 56))
// __BYTE_ORDER__ and __ORDER_BYTE_ORDER__ are macros defined by gcc
// use different check when compiling with a compiler that doesnt define them
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define HTOLE64(x) (x)
#else
#define HTOLE64(x) bswap_constant_64(x)
#endif
// yes a constant expression
static unsigned long long mynumber = HTOLE64(0x65736c6166ull);
int main() {
char bytes[sizeof(mynumber)];
memcpy(bytes, &mynumber, sizeof(mynumber));
// works on any endianess
assert(bytes[0] == 0x66);
assert(bytes[1] == 0x61);
}
Upvotes: 0
Reputation: 215259
While it's not an integer constant expression, you can define for example:
#define X ((union { unsigned char r[8]; uint64_t v; }){ 0x65, 0x73, 0x6c, 0x61, 0x66 }.v)
and X
now expands to an expression of type uint64_t
defined in terms of its representation not its value.
Upvotes: 1