The in6_addr structure stores the address in network byte order - or the "big end" - with the most significant byte @ s6_addr[0] . You cannot count on other members of the union to be successively named or identified. Even if you accessed the union through the (non-portable) uint32_t field, the values would have to be converted using ntohl . Therefore, the portable method of finding the difference requires some work.
You can convert in6_addr to uint64_t[2] . When using typical bignum conventions, we use [0] for low 64-bit and [1] for high 64-bit:
static inline void in6_to_u64 (uint64_t dst[2], const struct in6_addr *src) { uint64_t hi = 0, lo = 0; for (unsigned int i = 0; i < 8; i++) { hi = (hi << 8) | src->s6_addr[i]; lo = (lo << 8) | src->s6_addr[i + 8]; } dst[0] = lo, dst[1] = hi; }
and the difference is:
static inline unsigned int u64_diff (uint64_t d[2], const uint64_t x[2], const uint64_t y[2]) { unsigned int b = 0, bi; for (unsigned int i = 0; i < 2; i++) { uint64_t di, xi, yi, tmp; xi = x[i], yi = y[i]; tmp = xi - yi; di = tmp - b, bi = tmp > xi; d[i] = di, b = bi | (di > tmp); } return b; }
source share