Re: Canonical way / best practice for 128-bit integers

From: Dimitry Andric <dim_at_FreeBSD.org>
Date: Sat, 09 Jul 2022 17:04:56 UTC
On 9 Jul 2022, at 18:26, Marc Veldman <marc@bumblingdork.com> wrote:
> 
> I’m working on some bluetooth code, and that involves handling 128-bit uuids.
> There are various ways to handle in the FreeBSD codebase, like in sdp.h:
> 
> /*
> * SDP int128/uint128 parameter
> */
> 
> struct int128 {
>        int8_t  b[16];
> };
> typedef struct int128   int128_t;
> typedef struct int128   uint128_t;
> 
> and in sys/dev/random/uint128.h
> 
> #ifdef USE_REAL_UINT128_T
> typedef __uint128_t uint128_t;
> #define UINT128_ZERO 0ULL
> #else
> typedef struct {
>        /* Ignore endianness */
>        uint64_t u128t_word0;
>        uint64_t u128t_word1;
> } uint128_t;
> static const uint128_t very_long_zero = {0UL,0UL};
> #define UINT128_ZERO very_long_zero
> #endif
> 
> Is there any recommended / standard way to handle 128 bit integers in a portable way?

Of course recent compilers have built-in support for __int128_t and
__uint128_t, but it comes with a *lot* of caveats: not supported on all
architectures, definitely never on 32-bit ones, differences between
compilers, and even compiler versions, etc etc.

If you want it portable, the only way is to handle them as two 64 bit
integers, and leave any arithmetic or conversion to library routines.

-Dimitry