5
\$\begingroup\$

When working on my projects, I often need a 128-bit integer type. For this purpose, I use the __int128 compiler extension. Here is the implementation I am currently using:

/**
 * Support for 128-bit integers.
 */

#ifndef WIDEINT_WIDEINT_H_
#define WIDEINT_WIDEINT_H_

/* all GNU compilers */
#if defined(__GNUC__)

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wpedantic"
#pragma GCC diagnostic ignored "-pedantic"
typedef unsigned __int128 uint128_t;
#pragma GCC diagnostic pop

#define UINT128_C(n) ((uint128_t)n)
#define UINT128_MAX (~UINT128_C(0))

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wpedantic"
#pragma GCC diagnostic ignored "-pedantic"
typedef __int128 int128_t;
#pragma GCC diagnostic pop

#define INT128_C(n) ((int128_t)n)
#define INT128_MAX ((int128_t)(UINT128_MAX >> 1))
#define INT128_MIN (-INT128_MAX - 1)

#else
#   error "Unsupported compiler"
#endif /* defined(__GNUC__) */

#endif /* WIDEINT_WIDEINT_H_ */

As you can see, the implementation is quite complex.

My questions are: Is it possible to get rid of all those #pragmas? (For example, no #pragmas are needed in OpenCL.) Will my implementation work in all cases? (Currently, I am using C89.) Any suggestions for improvement or constructive criticism are welcome.

\$\endgroup\$
0

2 Answers 2

5
\$\begingroup\$

Consider the future when uint128_t is standard and available

You don't want your code to stomp on standard names, yet not require much code change.

Rather than uint128_t, UINT128_C, UINT128_MAX and the signed counterparts, use a different naming scheme like my_....

You could then add code that selectively brings in your code.

#include <stdint.h>
// Only use the user version of uint128_t if not defined by the standard library.
#ifndef UINT128_MAX
  #define UINT128_MAX MY_UINT128_MAX 
  #define UINT128_C MY_UINT128_C 
  typedef my_uint128_t uint128_t;
  ...
  // or stuff all your code here without the `my_`.
  #include "users_int128.h"
#endif

Future Ideas

Certainly functions like strtoint128(), sprint_int128(), int128_t round128(double), ... would be useful.

PRId128 SCNd128 and friends would be nice, but you might not be able to supply them.

\$\endgroup\$
0
1
\$\begingroup\$

I don't believe it's necessary to duplicate the the diagnostic pragma sequence. Just ignore those diagnostics once at the beginning of the #if block and pop the previous state at the end.

That simplifies maintenance if you ever need to change the set of suppressed warnings.

\$\endgroup\$
1
  • \$\begingroup\$ What about typedef unsigned uint128_t __attribute__ ((mode (TI)));? It does not require the diagnostic #pragmas and I noticed that it generates the same assembly. I don't know about compatibility though. \$\endgroup\$
    – DaBler
    Jan 16, 2023 at 14:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.