I'm trying to improve the portability of a file format converter, specifically to POSIX platforms other than Linux. I'd appreciate a review of the following functions used for converting between little endian and host endian 32bit unsigned integers and back. This is basically to replace le32toh
and htole32
on platforms where they are not available. I'd particularly appreciate comments on whether this violates strict aliasing, I believe accessing integers through a char pointer is allowed but I'm not 100% sure.
I am intentionally writing endian-neutral code, performance is not so critical and simplicity, reusability and portability are more important to me. Determining endianness at compile time is difficult across compilers and operating systems, runtime checks either incur their own overhead if they need to be run on each function call or require a global variable.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <inttypes.h>
uint32_t
le_u32_to_cpu(uint32_t le32)
{
unsigned char *b = (unsigned char *)&le32;
uint32_t cpu_u32 = b[0] | \
(b[1] << 8) | \
(b[2] << 16) | \
(b[3] << 24);
return (cpu_u32);
}
uint32_t
cpu_to_le_u32(uint32_t cpu_u32)
{
uint32_t le_u32;
unsigned char *b = (unsigned char *)&le_u32;
b[0] = cpu_u32 & 0xff;
b[1] = (cpu_u32 >> 8) & 0xff;
b[2] = (cpu_u32 >> 16) & 0xff;
b[3] = (cpu_u32 >> 24) & 0xff;
return (le_u32);
}
int
main(void)
{
uint32_t x;
unsigned char *b = (unsigned char *)&x;
b[0] = 0x11;
b[1] = 0x22;
b[2] = 0x33;
b[3] = 0x44;
puts("little endian");
for (size_t i = 0; i < 4; i++) {
printf("%02x\n", b[i]);
}
printf("0x%" PRIx32 "\n", x);
puts("cpu endianness");
x = le_u32_to_cpu(x);
for (size_t i = 0; i < 4; i++) {
printf("%02x\n", b[i]);
}
printf("0x%" PRIx32 "\n", x);
puts("back to little endian");
x = cpu_to_le_u32(x);
for (size_t i = 0; i < 4; i++) {
printf("%02x\n", b[i]);
}
printf("0x%" PRIx32 "\n", x);
return (0);
}
unsigned char
, then the union would be necessary to avoid strict aliasing issues.float
->uint32_t
ordouble
->uint64_t
would need a union. Butunsigned char
is the one escape valve type that allows pointer-punning for a reinterpretation of the stored object. ... Using a union might be better style since it extends to other conversions not involvingunsigned char
. \$\endgroup\$