In my own TCP/IP stack I have defined things like IPv4 addresses and port numbers as unions instead of integers, and given them functions to convert to host order and back. e.g.
typedef union {
uint32_t net_order;
uint8_t byte[4];
} ipv4_address;
_Static_assert( sizeof(ipv4_address) == 4, "ipv4_address is not 4 bytes long");
static inline __attribute__((overloadable)) uint32_t as_host( ipv4_address a) {
return other_order_32(a.net_order);
}
// more functions follow, like
// bool equal(a,b)
// int compare(a,b)
// ipv4_address ipv4_address_from_host( uint32_t)
The nice part of this is that it would take an act of willful ignorance on my part to accidentally miss or over include a conversion from network order to host order.
The compiler is still happy to slam these around in registers like integers so I haven't changed the runtime performance. The downside is that C won't let you compare structs or unions with ==, so I have to have that equal() function which dirties the source code a bit.
That __attribute__((overloadable)) makes as_host() an overloadable function so I don't have to have a giant family of incredibly_long_function_names to convert all my different types to host byte order or to compare them with themselves.
That _Static_assert isn't terribly useful in this case, but there is one on all of the structures where I expect to have explicitly specified a layout. That way when the compiler tries to pull a fast one on me because some language lawyer spent too long reading the spec, I'll find out at build time.
The compiler is still happy to slam these around in registers like integers so I haven't changed the runtime performance. The downside is that C won't let you compare structs or unions with ==, so I have to have that equal() function which dirties the source code a bit.
That __attribute__((overloadable)) makes as_host() an overloadable function so I don't have to have a giant family of incredibly_long_function_names to convert all my different types to host byte order or to compare them with themselves.
That _Static_assert isn't terribly useful in this case, but there is one on all of the structures where I expect to have explicitly specified a layout. That way when the compiler tries to pull a fast one on me because some language lawyer spent too long reading the spec, I'll find out at build time.