#ifndef TERRY_H #define TERRY_H #if 0 Promises the most accurate primitives as are allowable by (recent) compiler version and C standard. Primitivie types: signed int : i8>i128, s8>s128 unsigned int : u8>u128 float : f, f32 double : fl, f64 long double : fll, f128 NO_128_TYPES will not be defined if i128, s128, u128 exist. NO_F_TYPE_NAME will remove hazardous declarations of f, fl, and fll. all floating bitmarked types will have F_PRECISE defined if they are specified to that precise number of bits. Tested to work with gcc 14.2.0 and clang 19.1.7 on Debian Backwards compat for gcc 14.2.0 Not robustly tested, please report issues. --- Definitions --- Defining the following will change behavior within the typesystem. the IMPRECISE groupings will always be provided with their respective types are present in full. #define TERRY_FLOAT_IMPRECISE /* supergroup of the below two groups */ #define TERRY_SMALL_FLOAT_IMPRECISE /* groups the two below together */ #define FLOAT_IS_F32 #define DOUBLE_IS_F64 #define TERRY_LARGE_FLOAT_IMPRECISE /* groups the two below together */ #define LONG_DOUBLE_IS_F80 #define LONG_DOUBLE_IS_F128 #define NO_128_TYPES /* removes 128 declarations */ #define NO_F_TYPE_NAME /* removes hazardous f, fl, fll */ #endif /* --- */ #include typedef int8_t i8; typedef int16_t i16; typedef int32_t i32; typedef int64_t i64; typedef int8_t s8; typedef int16_t s16; typedef int32_t s32; typedef int64_t s64; typedef uint8_t u8; typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; #ifndef NO_F_TYPE_NAME typedef float f; typedef double fl; typedef long double fll; #endif #ifndef NO_128_TYPES # if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L && defined(__GNUC__) && !defined(__clang__)) \ || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) # define PRECISE_128 typedef signed _BitInt(128) i128; typedef signed _BitInt(128) s128; typedef unsigned _BitInt(128) u128; # else # if __SIZEOF_INT128__ /* compiler specific macro */ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpedantic" # define PRECISE_128 typedef signed __int128 i128; typedef signed __int128 s128; typedef unsigned __int128 u128; # pragma GCC diagnostic pop # else # define NO_128_TYPES # endif # endif #endif #if !(defined(__STDC_IEC_60559_BFP__) && defined(__STDC_IEC_60559_TYPES__)) #define TERRY_FLOAT_IMPRECISE #endif #ifdef TERRY_FLOAT_IMPRECISE # define TERRY_SMALL_FLOAT_IMPRECISE # define TERRY_LARGE_FLOAT_IMPRECISE #endif #ifdef TERRY_SMALL_FLOAT_IMPRECISE # define FLOAT_IS_F32 # define DOUBLE_IS_F64 #endif #ifdef TERRY_LARGE_FLOAT_IMPRECISE # define LONG_DOUBLE_IS_F80 # define LONG_DOUBLE_IS_F128 #endif /* You can treat floats like _Float32, and doubles like _Float64, however *THEY ARE NOT THE SAME THING*. */ /* go ask WG14 for the "why." GCC/Clang may complain but will work as expected. */ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202000L && defined(__GNUC__) && !defined(__clang__)) \ || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L) # if defined(FLOAT_IS_F32) || defined(TERRY_SMALL_FLOAT_IMPRECISE) typedef float f32; # else # define F32_PRECISE typedef _Float32 f32; # endif # if defined(DOUBLE_IS_F64) || defined(TERRY_LARGE_FLOAT_IMPRECISE) typedef double f64; # else # define F64_PRECISE typedef _Float64 f64; # endif # if defined(__GNUC__) && !defined(__clang__) # define F80_PRECISE typedef __float80 f80; # else #define LONG_DOUBLE_IS_F80 typedef long double f80; # endif # if defined(LONG_DOUBLE_IS_F128) || defined(TERRY_LARGE_FLOAT_IMPRECISE) typedef long double f128; # else # define F128_PRECISE typedef _Float128 f128; # endif #else /* the below f32/64 definitions may behave erratically, as float != f32 && double != f64. * We're just doing this for the sake of defining something that will *probably* work in most cases. * Use newer C versions. */ # if defined(__GNUC__) && !defined(__clang__) # define TERRY_SMALL_FLOAT_IMPRECISE # define FLOAT_IS_F32 typedef float f32; # define DOUBLE_IS_F64 typedef double f64; # if defined(LONG_DOUBLE_IS_F80) typedef long double f80; # else # define F80_PRECISE typedef __float80 f80; # endif # if defined(LONG_DOUBLE_IS_F128) typedef long double f128; # else # define F128_PRECISE typedef __float128 f128; # endif # else # define TERRY_FLOAT_IMPRECISE # define TERRY_SMALL_FLOAT_IMPRECISE # define TERRY_LARGE_FLOAT_IMPRECISE # define FLOAT_IS_F32 typedef float f32; # define DOUBLE_IS_F64 typedef double f64; /* Usually 10-bytes with 128-bit alignment */ # define LONG_DOUBLE_IS_F80 typedef long double f80; # define LONG_DOUBLE_IS_F128 typedef long double f128; # endif #endif #endif