/* type_s64.h Define 64-bit integer data types, based on user-supplied options of compiler-supplied #defines if available. In the 1990's (Metrowerks projects, notably Power MANDELZOOM) I used my C++ library "i64_o.c" to get 64-bit integers. PMZ is the only project I have that still uses it. Compiler-provided definitions can be seen with "show_predefs.h" or a command like: gcc -dM -E - < /dev/null | sort Here is a partial list of compiler defines that can be used to figure out the size of pointer and long. They are used like this: #if (defined(__foo__) && defined(__bar__)) width defines 64 _AIX && __64BIT__ 64 __hpux && __LP64__ 32 __linux__ && __i386__ 64 __linux__ && __ia64__ 64 __linux__ && __x86_64__ 32 __linux__ && __powerpc__ 64 __linux__ && __powerpc64__ 32 __linux__ && __s390__ 64 __linux__ && __s390x__ 64 __osf__ 64 sinix && __LP64__ 64 _WIN64 32 _WIN32 For Sun you need to test for either "sun" or "__sun", and if either of these is defined, include then test for "_LP64". To get a 64-bit int in Microsoft visual C++ (i.e. in both _WIN32 and _WIN64), you can use "__int64" and "unsigned __int64". To get 64-bit int in Linux (i.e. __linux__) and in MacOS X (i.e. __APPLE__ && __MACH__) you can include and then use "int64_t" and "uint64_t". Otherwise test the other combinations in the list above (e.g. __hpux && __LP64__) to find out if "long" is 64-bit, and if it isn't, use "long long" to get 64-bit. "long long" is part of the C99 standard; by extension GCC has provided it in C90 and C++ modes since the late 1990's. You can use #ifdef __GNUC__ followed by an #if expression including __GNUC__ and __GNUC_MINOR__ to determine if your specific GCC version includes it. REVISION HISTORY: 20191019 Use __int64 on Windows systems 20241104 Test for __INT64_TYPE__ before the user-supplied options. Add #ifndef HAVE_S64 around the __GNUC__ test. 20241106 Add section to self-configure via __LONG_WIDTH__ etc. 20241107 Try __LONG_MAX__ before __LONG_LONG_MAX__ */ /* First try to figure it out ourselves by testing the predefined macros given by GCC, and from these generate the 'user-defined options' */ #ifdef S64_DETECTED # undef S64_DETECTED #endif #ifdef __LONG_WIDTH__ /* newer GCC compilers e.g. Linux gcc 9.x with -m64 or x86_64 binary option */ # if __LONG_WIDTH__ == 64 # undef LONG_IS_S64 # undef LONGLONG_IS_S64 # define LONG_IS_S64 # define S64_DETECTED # endif #endif #ifndef S64_DETECTED # ifdef __LONG_MAX__ /* Older GCC compilers do not define __LONG_WIDTH__ but do have __LONG_MAX__ */ # if (__LONG_MAX__>>32) > 0 # undef LONG_IS_S64 # undef LONGLONG_IS_S64 # define LONG_IS_S64 # define S64_DETECTED # endif # endif /* __LONG_LONG_MAX__ */ #endif /* S64_DETECTED */ #ifndef S64_DETECTED # ifdef __LONG_LONG_MAX__ /* Older GCC compilers e.g. 4.0.x on old Macs, have 32-bit 'long' but provide 'long long' */ # if (__LONG_LONG_MAX__>>32) > 0 # undef LONG_IS_S64 # undef LONGLONG_IS_S64 # define LONGLONG_IS_S64 # define S64_DETECTED # endif # endif /* __LONG_LONG_MAX__ */ #endif /* S64_DETECTED */ /* %%% I can also test INT_MAX defined in . For portability I can include the header only if USE_LIMITS_H is defined. */ /* For a few days I was starting the following with: #ifdef __INT64_TYPE__ typedef __INT64_TYPE__ s64; typedef __UINT64_TYPE__ u64; # define HAVE_S64 */ /* First check user-supplied options */ #ifdef LONGLONG_IS_S64 typedef signed long long int s64; typedef unsigned long long int u64; # define HAVE_S64 #else # ifdef LONG_IS_S64 typedef signed long int s64; typedef unsigned long int u64; # define HAVE_S64 # else # ifdef DUNDER_INT64_IS_S64 typedef __int64 s64; typedef unsigned __int64 u64; # define HAVE_S64 # endif # endif #endif /* Next check things defined by compilers. */ /* NOTE: Very early GCC probably does not provide long long. */ #ifndef HAVE_S64 # ifdef __GNUC__ typedef signed long long int s64; typedef unsigned long long int u64; # define HAVE_S64 # endif #endif /* Early Microsoft compilers definitely do not provide "long long". It is safe to use __int64 unless your MSFT compiler is so old that it doesn't provide any 64-bit int type, in which case it's hopeless. */ #if (defined(_WIN32) || defined(_WIN64)) # define DUNDER_INT64_IS_S64 #endif #ifndef HAVE_S64 # ifdef DUNDER_INT64_IS_S64 typedef __int64 s64; typedef unsigned __int64 u64; # define HAVE_S64 # endif #endif /* Last deperate effort to define something, if we weren't alredy able to figure it out */ #ifndef HAVE_S64 typedef signed long long int s64; typedef unsigned long long int u64; # define HAVE_S64 #endif /* This macro provides code that you can use at runtime (e.g. at the beginning of your main) to make sure s64 is actually 64 bits. It assumes is already included. We don't include stdio for you because perhaps you don't want to use this macro. */ #ifndef TYPE_S64_CHECK_SIZE # define TYPE_S64_CHECK_SIZE(procname) \ if (sizeof(s64) != 8) { \ printf("%s: s64 is not 8 bytes (got %d).\n", \ (procname), (int) sizeof(s64)); \ if (sizeof(long) == 8) { \ printf( \ " To fix this error, recompile with the flag -DLONG_IS_S64\n"); \ } else if (sizeof(long long) == 8) { \ printf( \ " To fix this error, recompile with the flag -DLONGLONG_IS_S64\n"); \ } else { \ printf( \ " (presently, sizeof(long)==%d and sizeof(long long)==%d)\n", \ (int) sizeof(long), (int) sizeof(long long)); \ } \ exit(-1); \ } #endif