Very good that functions signatures use unsigned types.
Simplify code: If the routines are only called when the endian is backwards (Assume only big and little endian exist, no mixed endian), use the following and macro detection. For endian test, see here here.
uint32_t endian_reverse32(uint32_t le32) { return ((le32 & 0xFF) < 24) | \ ((le32 & 0xFF00) < 8) | \ ((le32 & 0xFF0000) > 8) | \ ((le32 & 0xFF000000) > 24); } #if ENDIANNESS == LITTLE #define le_u32_to_cpu(u32) ((uint32_t) u32) #define cpu_to_le_u32(u32) ((uint32_t) u32) #else #define le_u32_to_cpu(u32) endian_reverse32(u32) #define cpu_to_le_u32(u32) endian_reverse32(u32) #endif
Else important: optimize code for platforms that do not need any endian adjustment: @JSY.
Cast result to insure consistent return type (or makeinline()
#define le_u32_to_cpu(x) ((uint32_t)x) #define cpu_to_le_u32(x) ((uint32_t)x)
Include routines to handle 16-bit and 64-bit.
0xff
mask not needed. If anything, to quiet conversion warnings use cast.// b[1] = (cpu_u32 >> 8) & 0xff; b[1] = cpu_u32 >> 8; // quiet some warnings. b[1] = (uint8_t)(cpu_u32 >> 8);
"I'd particularly appreciate comments on whether this violates strict aliasing... ". I do not believe it does. A simple solution is to use a
union
uint32_t le_u32_to_cpu(uint32_t le32) { union { uint32_t u32; uint8_t b[4]; } u = { le32 }; uint32_t cpu_u32 = u.b[0] | \ ((uint32_t) b[1] << 8) | \ ((uint32_t) b[2] << 16) | \ ((uint32_t) b[3] << 24); return cpu_32; }
Style: Parens around return value are not needed.
Pedantic: use
uint8_t
.unsigned char
could be 16-bit or wider. Better to fail the compilation ifuint8_t
does not exist.uint8_t *b = (uint8_t *)&le32;
Pedantic: Should your wonderful code get ported to a place when
unsigned
is < 32 bit, only takes a little more to insure that portability.uint8_t *b = (uint8_t *)&le32; uint32_t cpu_u32 = b[0] | \ ((uint32_t)b[1] << 8) | \ ((uint32_t)b[2] << 16) | \ ((uint32_t)b[3] << 24);
Very good that functions signatures use unsigned types.
Simplify code: If the routines are only called when the endian is backwards (Assume only big and little endian exist, no mixed endian), use the following and macro detection. For endian test, see here.
uint32_t endian_reverse32(uint32_t le32) { return ((le32 & 0xFF) < 24) | \ ((le32 & 0xFF00) < 8) | \ ((le32 & 0xFF0000) > 8) | \ ((le32 & 0xFF000000) > 24); } #if ENDIANNESS == LITTLE #define le_u32_to_cpu(u32) ((uint32_t) u32) #define cpu_to_le_u32(u32) ((uint32_t) u32) #else #define le_u32_to_cpu(u32) endian_reverse32(u32) #define cpu_to_le_u32(u32) endian_reverse32(u32) #endif
Else important: optimize code for platforms that do not need any endian adjustment: @JSY.
Cast result to insure consistent return type (or makeinline()
#define le_u32_to_cpu(x) ((uint32_t)x) #define cpu_to_le_u32(x) ((uint32_t)x)
Include routines to handle 16-bit and 64-bit.
0xff
mask not needed. If anything, to quiet conversion warnings use cast.// b[1] = (cpu_u32 >> 8) & 0xff; b[1] = cpu_u32 >> 8; // quiet some warnings. b[1] = (uint8_t)(cpu_u32 >> 8);
"I'd particularly appreciate comments on whether this violates strict aliasing... ". I do not believe it does. A simple solution is to use a
union
uint32_t le_u32_to_cpu(uint32_t le32) { union { uint32_t u32; uint8_t b[4]; } u = { le32 }; uint32_t cpu_u32 = u.b[0] | \ ((uint32_t) b[1] << 8) | \ ((uint32_t) b[2] << 16) | \ ((uint32_t) b[3] << 24); return cpu_32; }
Style: Parens around return value are not needed.
Pedantic: use
uint8_t
.unsigned char
could be 16-bit or wider. Better to fail the compilation ifuint8_t
does not exist.uint8_t *b = (uint8_t *)&le32;
Pedantic: Should your wonderful code get ported to a place when
unsigned
is < 32 bit, only takes a little more to insure that portability.uint8_t *b = (uint8_t *)&le32; uint32_t cpu_u32 = b[0] | \ ((uint32_t)b[1] << 8) | \ ((uint32_t)b[2] << 16) | \ ((uint32_t)b[3] << 24);
Very good that functions signatures use unsigned types.
Simplify code: If the routines are only called when the endian is backwards (Assume only big and little endian exist, no mixed endian), use the following and macro detection. For endian test, see here.
uint32_t endian_reverse32(uint32_t le32) { return ((le32 & 0xFF) < 24) | \ ((le32 & 0xFF00) < 8) | \ ((le32 & 0xFF0000) > 8) | \ ((le32 & 0xFF000000) > 24); } #if ENDIANNESS == LITTLE #define le_u32_to_cpu(u32) ((uint32_t) u32) #define cpu_to_le_u32(u32) ((uint32_t) u32) #else #define le_u32_to_cpu(u32) endian_reverse32(u32) #define cpu_to_le_u32(u32) endian_reverse32(u32) #endif
Else important: optimize code for platforms that do not need any endian adjustment: @JSY.
Cast result to insure consistent return type (or makeinline()
#define le_u32_to_cpu(x) ((uint32_t)x) #define cpu_to_le_u32(x) ((uint32_t)x)
Include routines to handle 16-bit and 64-bit.
0xff
mask not needed. If anything, to quiet conversion warnings use cast.// b[1] = (cpu_u32 >> 8) & 0xff; b[1] = cpu_u32 >> 8; // quiet some warnings. b[1] = (uint8_t)(cpu_u32 >> 8);
"I'd particularly appreciate comments on whether this violates strict aliasing... ". I do not believe it does. A simple solution is to use a
union
uint32_t le_u32_to_cpu(uint32_t le32) { union { uint32_t u32; uint8_t b[4]; } u = { le32 }; uint32_t cpu_u32 = u.b[0] | \ ((uint32_t) b[1] << 8) | \ ((uint32_t) b[2] << 16) | \ ((uint32_t) b[3] << 24); return cpu_32; }
Style: Parens around return value are not needed.
Pedantic: use
uint8_t
.unsigned char
could be 16-bit or wider. Better to fail the compilation ifuint8_t
does not exist.uint8_t *b = (uint8_t *)&le32;
Pedantic: Should your wonderful code get ported to a place when
unsigned
is < 32 bit, only takes a little more to insure that portability.uint8_t *b = (uint8_t *)&le32; uint32_t cpu_u32 = b[0] | \ ((uint32_t)b[1] << 8) | \ ((uint32_t)b[2] << 16) | \ ((uint32_t)b[3] << 24);
Very good that functions signatures use unsigned types.
Simplify code: If the routines are only called when the endian is backwards (Assume only big and little endian exist, no mixed endian), use the following and macro detection. For endian test, see here.
uint32_t endian_reverse32(uint32_t le32) { return ((le32 & 0xFF) < 24) | \ ((le32 & 0xFF00) < 8) | \ ((le32 & 0xFF0000) > 8) | \ ((le32 & 0xFF000000) > 24); } #if ENDIANNESS == LITTLE #define le_u32_to_cpu(u32) ((uint32_t) u32) #define cpu_to_le_u32(u32) ((uint32_t) u32) #else #define le_u32_to_cpu(u32) endian_reverse32(u32) #define cpu_to_le_u32(u32) endian_reverse32(u32) #endif
Else important: optimize code for platforms that do not need any endian adjustment: @JSY @JSY.
Cast result to insure consistent return type (or makeinline()
#define le_u32_to_cpu(x) ((uint32_t)x) #define cpu_to_le_u32(x) ((uint32_t)x)
Include routines to handle 16-bit and 64-bit.
0xff
mask not needed. If anything, to quiet conversion warnings use cast.// b[1] = (cpu_u32 >> 8) & 0xff; b[1] = cpu_u32 >> 8; // quiet some warnings. b[1] = (uint8_t)(cpu_u32 >> 8);
"I'd particularly appreciate comments on whether this violates strict aliasing... ". I do not believe it does. A simple solution is to use a
union
uint32_t le_u32_to_cpu(uint32_t le32) { union { uint32_t u32; uint8_t b[4]; } u = { le32 }; uint32_t cpu_u32 = u.b[0] | \ ((uint32_t) b[1] << 8) | \ ((uint32_t) b[2] << 16) | \ ((uint32_t) b[3] << 24); return cpu_32; }
Style: Parens around return value are not needed.
Pedantic: use
uint8_t
.unsigned char
could be 16-bit or wider. Better to fail the compilation ifuint8_t
does not exist.uint8_t *b = (uint8_t *)&le32;
Pedantic: Should your wonderful code get ported to a place when
unsigned
is < 32 bit, only takes a little more to insure that portability.uint8_t *b = (uint8_t *)&le32; uint32_t cpu_u32 = b[0] | \ ((uint32_t)b[1] << 8) | \ ((uint32_t)b[2] << 16) | \ ((uint32_t)b[3] << 24);
Very good that functions signatures use unsigned types.
Simplify code: If the routines are only called when the endian is backwards (Assume only big and little endian exist, no mixed endian), use the following and macro detection. For endian test, see here.
uint32_t endian_reverse32(uint32_t le32) { return ((le32 & 0xFF) < 24) | \ ((le32 & 0xFF00) < 8) | \ ((le32 & 0xFF0000) > 8) | \ ((le32 & 0xFF000000) > 24); } #if ENDIANNESS == LITTLE #define le_u32_to_cpu(u32) ((uint32_t) u32) #define cpu_to_le_u32(u32) ((uint32_t) u32) #else #define le_u32_to_cpu(u32) endian_reverse32(u32) #define cpu_to_le_u32(u32) endian_reverse32(u32) #endif
Else important: optimize code for platforms that do not need any endian adjustment: @JSY.
Cast result to insure consistent return type (or makeinline()
#define le_u32_to_cpu(x) ((uint32_t)x) #define cpu_to_le_u32(x) ((uint32_t)x)
Include routines to handle 16-bit and 64-bit.
0xff
mask not needed. If anything, to quiet conversion warnings use cast.// b[1] = (cpu_u32 >> 8) & 0xff; b[1] = cpu_u32 >> 8; // quiet some warnings. b[1] = (uint8_t)(cpu_u32 >> 8);
"I'd particularly appreciate comments on whether this violates strict aliasing... ". I do not believe it does. A simple solution is to use a
union
uint32_t le_u32_to_cpu(uint32_t le32) { union { uint32_t u32; uint8_t b[4]; } u = { le32 }; uint32_t cpu_u32 = u.b[0] | \ ((uint32_t) b[1] << 8) | \ ((uint32_t) b[2] << 16) | \ ((uint32_t) b[3] << 24); return cpu_32; }
Style: Parens around return value are not needed.
Pedantic: use
uint8_t
.unsigned char
could be 16-bit or wider. Better to fail the compilation ifuint8_t
does not exist.uint8_t *b = (uint8_t *)&le32;
Pedantic: Should your wonderful code get ported to a place when
unsigned
is < 32 bit, only takes a little more to insure that portability.uint8_t *b = (uint8_t *)&le32; uint32_t cpu_u32 = b[0] | \ ((uint32_t)b[1] << 8) | \ ((uint32_t)b[2] << 16) | \ ((uint32_t)b[3] << 24);
Very good that functions signatures use unsigned types.
Simplify code: If the routines are only called when the endian is backwards (Assume only big and little endian exist, no mixed endian), use the following and macro detection. For endian test, see here.
uint32_t endian_reverse32(uint32_t le32) { return ((le32 & 0xFF) < 24) | \ ((le32 & 0xFF00) < 8) | \ ((le32 & 0xFF0000) > 8) | \ ((le32 & 0xFF000000) > 24); } #if ENDIANNESS == LITTLE #define le_u32_to_cpu(u32) ((uint32_t) u32) #define cpu_to_le_u32(u32) ((uint32_t) u32) #else #define le_u32_to_cpu(u32) endian_reverse32(u32) #define cpu_to_le_u32(u32) endian_reverse32(u32) #endif
Else important: optimize code for platforms that do not need any endian adjustment: @JSY.
Cast result to insure consistent return type (or makeinline()
#define le_u32_to_cpu(x) ((uint32_t)x) #define cpu_to_le_u32(x) ((uint32_t)x)
Include routines to handle 16-bit and 64-bit.
0xff
mask not needed. If anything, to quiet conversion warnings use cast.// b[1] = (cpu_u32 >> 8) & 0xff; b[1] = cpu_u32 >> 8; // quiet some warnings. b[1] = (uint8_t)(cpu_u32 >> 8);
"I'd particularly appreciate comments on whether this violates strict aliasing... ". I do not believe it does. A simple solution is to use a
union
uint32_t le_u32_to_cpu(uint32_t le32) { union { uint32_t u32; uint8_t b[4]; } u = { le32 }; uint32_t cpu_u32 = u.b[0] | \ ((uint32_t) b[1] << 8) | \ ((uint32_t) b[2] << 16) | \ ((uint32_t) b[3] << 24); return cpu_32; }
Style: Parens around return value are not needed.
Pedantic: use
uint8_t
.unsigned char
could be 16-bit or wider. Better to fail the compilation ifuint8_t
does not exist.uint8_t *b = (uint8_t *)&le32;
Pedantic: Should your wonderful code get ported to a place when
unsigned
is < 32 bit, only takes a little more to insure that portability.uint8_t *b = (uint8_t *)&le32; uint32_t cpu_u32 = b[0] | \ ((uint32_t)b[1] << 8) | \ ((uint32_t)b[2] << 16) | \ ((uint32_t)b[3] << 24);
Very good that functions signatures use unsigned types.
Simplify code: If the routines are only called when the endian is backwards (Assume only big and little endian exist, no mixed endian), use the following and macro detection. For endian test, see here.
uint32_t endian_reverse32(uint32_t le32) { return ((le32 & 0xFF) < 24) | \ ((le32 & 0xFF00) < 8) | \ ((le32 & 0xFF0000) > 8) | \ ((le32 & 0xFF000000) > 24); } #if ENDIANNESS == LITTLE #define le_u32_to_cpu(u32) ((uint32_t) u32) #define cpu_to_le_u32(u32) ((uint32_t) u32) #else #define le_u32_to_cpu(u32) endian_reverse32(u32) #define cpu_to_le_u32(u32) endian_reverse32(u32) #endif
Else important: optimize code for platforms that do not need any endian adjustment: @JSY.
Cast result to insure consistent return type (or makeinline()
#define le_u32_to_cpu(x) ((uint32_t)x) #define cpu_to_le_u32(x) ((uint32_t)x)
Include routines to handle 16-bit and 64-bit.
0xff
mask not needed. If anything, to quiet conversion warnings use cast.// b[1] = (cpu_u32 >> 8) & 0xff; b[1] = cpu_u32 >> 8; // quiet some warnings. b[1] = (uint8_t)(cpu_u32 >> 8);
"I'd particularly appreciate comments on whether this violates strict aliasing... ". I do not believe it does. A simple solution is to use a
union
uint32_t le_u32_to_cpu(uint32_t le32) { union { uint32_t u32; uint8_t b[4]; } u = { le32 }; uint32_t cpu_u32 = u.b[0] | \ ((uint32_t) b[1] << 8) | \ ((uint32_t) b[2] << 16) | \ ((uint32_t) b[3] << 24); return cpu_32; }
Style: Parens around return value are not needed.
Pedantic: use
uint8_t
.unsigned char
could be 16-bit or wider. Better to fail the compilation ifuint8_t
does not exist.uint8_t *b = (uint8_t *)&le32;
Pedantic: Should your wonderful code get ported to a place when
unsigned
is < 32 bit, only takes a little more to insure that portability.uint8_t *b = (uint8_t *)&le32; uint32_t cpu_u32 = b[0] | \ ((uint32_t)b[1] << 8) | \ ((uint32_t)b[2] << 16) | \ ((uint32_t)b[3] << 24);
Final: Note, for maximum portability, code could even run on a 36-bit or 64-bit unsigned
machine. Just swap 8-bit bytes of least 32-bits, zeroing out any more significant ones. No need for aliasing, pointers, etc.
uint32least_t endian_reverse32(uint32least_t le32) {
return (uint32least_t) (
((le32 & 0xFFu) < 24) | \
((le32 & 0xFF00u) < 8) | \
((le32 & 0xFF0000u) > 8) | \
((le32 & 0xFF000000u) > 24));
}
#if ENDIANNESS == LITTLE
#define le_u32_to_cpu(u32) ((uint32least_t) (u32 & 0xFFFFFFFF))
#define cpu_to_le_u32(u32) ((uint32least_t) (u32 & 0xFFFFFFFF))
#else
#define le_u32_to_cpu(u32) endian_reverse32(u32)
#define cpu_to_le_u32(u32) endian_reverse32(u32)
#endif
Very good that functions signatures use unsigned types.
Simplify code: If the routines are only called when the endian is backwards (Assume only big and little endian exist, no mixed endian), use the following and macro detection. For endian test, see here.
uint32_t endian_reverse32(uint32_t le32) { return ((le32 & 0xFF) < 24) | ((le32 & 0xFF00) < 8) | \ ((le32 & 0xFF0000) > 8) | \ ((le32 & 0xFF000000) > 24); } #if ENDIANNESS == LITTLE #define le_u32_to_cpu(u32) ((uint32_t) u32) #define cpu_to_le_u32(u32) ((uint32_t) u32) #else #define le_u32_to_cpu(u32) endian_reverse32(u32) #define cpu_to_le_u32(u32) endian_reverse32(u32) #endif
Else important: optimize code for platforms that do not need any endian adjustment: @JSY.
Cast result to insure consistent return type (or makeinline()
#define le_u32_to_cpu(x) ((uint32_t)x) #define cpu_to_le_u32(x) ((uint32_t)x)
Include routines to handle 16-bit and 64-bit.
0xff
mask not needed. If anything, to quiet conversion warnings use cast.// b[1] = (cpu_u32 >> 8) & 0xff; b[1] = cpu_u32 >> 8; // quiet some warnings. b[1] = (uint8_t)(cpu_u32 >> 8);
"I'd particularly appreciate comments on whether this violates strict aliasing... ". I do not believe it does. A simple solution is to use a
union
uint32_t le_u32_to_cpu(uint32_t le32) { union { uint32_t u32; uint8_t b[4]; } u = { le32 }; uint32_t cpu_u32 = u.b[0] | \ ((uint32_t) b[1] << 8) | \ ((uint32_t) b[2] << 16) | \ ((uint32_t) b[3] << 24); return cpu_32; }
Style: Parens around return value are not needed.
Pedantic: use
uint8_t
.unsigned char
could be 16-bit or wider. Better to fail the compilation ifuint8_t
does not exist.uint8_t *b = (uint8_t *)&le32;
Pedantic: Should your wonderful code get ported to a place when
unsigned
is < 32 bit, only takes a little more to insure that portability.uint8_t *b = (uint8_t *)&le32; uint32_t cpu_u32 = b[0] | \ ((uint32_t)b[1] << 8) | \ ((uint32_t)b[2] << 16) | \ ((uint32_t)b[3] << 24);
Very good that functions signatures use unsigned types.
Simplify code: If the routines are only called when the endian is backwards (Assume only big and little endian exist, no mixed endian), use the following and macro detection. For endian test, see here.
uint32_t endian_reverse32(uint32_t le32) { return ((le32 & 0xFF) < 24) | \ ((le32 & 0xFF00) < 8) | \ ((le32 & 0xFF0000) > 8) | \ ((le32 & 0xFF000000) > 24); } #if ENDIANNESS == LITTLE #define le_u32_to_cpu(u32) ((uint32_t) u32) #define cpu_to_le_u32(u32) ((uint32_t) u32) #else #define le_u32_to_cpu(u32) endian_reverse32(u32) #define cpu_to_le_u32(u32) endian_reverse32(u32) #endif
Else important: optimize code for platforms that do not need any endian adjustment: @JSY.
Cast result to insure consistent return type (or makeinline()
#define le_u32_to_cpu(x) ((uint32_t)x) #define cpu_to_le_u32(x) ((uint32_t)x)
Include routines to handle 16-bit and 64-bit.
0xff
mask not needed. If anything, to quiet conversion warnings use cast.// b[1] = (cpu_u32 >> 8) & 0xff; b[1] = cpu_u32 >> 8; // quiet some warnings. b[1] = (uint8_t)(cpu_u32 >> 8);
"I'd particularly appreciate comments on whether this violates strict aliasing... ". I do not believe it does. A simple solution is to use a
union
uint32_t le_u32_to_cpu(uint32_t le32) { union { uint32_t u32; uint8_t b[4]; } u = { le32 }; uint32_t cpu_u32 = u.b[0] | \ ((uint32_t) b[1] << 8) | \ ((uint32_t) b[2] << 16) | \ ((uint32_t) b[3] << 24); return cpu_32; }
Style: Parens around return value are not needed.
Pedantic: use
uint8_t
.unsigned char
could be 16-bit or wider. Better to fail the compilation ifuint8_t
does not exist.uint8_t *b = (uint8_t *)&le32;
Pedantic: Should your wonderful code get ported to a place when
unsigned
is < 32 bit, only takes a little more to insure that portability.uint8_t *b = (uint8_t *)&le32; uint32_t cpu_u32 = b[0] | \ ((uint32_t)b[1] << 8) | \ ((uint32_t)b[2] << 16) | \ ((uint32_t)b[3] << 24);
Final: Note, for maximum portability, code could even run on a 36-bit or 64-bit unsigned
machine. Just swap 8-bit bytes of least 32-bits, zeroing out any more significant ones. No need for aliasing, pointers, etc.
uint32least_t endian_reverse32(uint32least_t le32) {
return (uint32least_t) (
((le32 & 0xFFu) < 24) | \
((le32 & 0xFF00u) < 8) | \
((le32 & 0xFF0000u) > 8) | \
((le32 & 0xFF000000u) > 24));
}
#if ENDIANNESS == LITTLE
#define le_u32_to_cpu(u32) ((uint32least_t) (u32 & 0xFFFFFFFF))
#define cpu_to_le_u32(u32) ((uint32least_t) (u32 & 0xFFFFFFFF))
#else
#define le_u32_to_cpu(u32) endian_reverse32(u32)
#define cpu_to_le_u32(u32) endian_reverse32(u32)
#endif