A single C header file which collects and normalizes hundreds on predefined processor macros.
Predefined macros and constants are essential to writing portable C/C++ code; unfortunately, due to these predefined constants never being standardised and there being many different equally-unintuitive conventions for naming them, finding and using these predefined macros can be a nightmare. I created this project to provide a single C header file which collects hundreds of these enigmatic macros, from the most common architectures/compilers/system to the most obscure and deprecated ones, and present them in a simple, consistent format.
The main "c_predefined.h" header file is designed to be a single-file, drop-in, pseudo-library (sort of in the spirit of Sean T Barret's single-file libs except even simpler); literally just place the "c_predefined.h" file in your source/include directory and you're good to go: no additional attributions, mandatory configuration, or external dependencies to worry about.
c_predefined.h wraps (or shadows) hundreds of C-preprocessor constants (#defines) for tons of architectures, compilers, and systems to be more consistent and clear. These shadowed macros are wrapped in new macros, all following the consistent naming format of C_<section>_<item> with <section> either being ARCHITECTURE, COMPILER, SYSTEM, or STANDARD and the <item> part being a specific architecture/compiler/system/standard: both written with all alphabetical characters in uppercase. Additionally, for the first three, architecture/compiler/system sections, omitting the item part, just using C_<section> gives you a human-readable string of the name of the most-applicable (meaning the most specific identifier which can be used to accurately describe that section for the current system/build environment) item for that section (more on this below).
To find out if a specific architecture is in use
#if C_ARCHITECTURE_<architecture name in all caps> == 1
or simply
#if define(C_ARCHITECTURE_<architecture name in all caps>) /* or #ifdef C_ARCHITECTURE_<capitalised architecture name> */
either of the above will be true if the specified architecture is the primary architecture in use.
Additionally, a human-readable and properly-cased string for whatever the current architecture is, is defined for C_ARCHITECTURE.
Note, c_predefined.h uses whatever the most-specific applicable architecture name is so, for example, it will use C_ARCHITECTURE_ARM64 over simply C_ARCHITECTURE_ARM on 64-bit ARM processors.
Full example:
#include "c_predefined.h"
#include <stdio.h>
int main(int argc, char *argv[]){
#if C_ARCHITECTURE_X86_64
printf("This code was compiled for %s architecture.", C_ARCHITECTURE); /* Will print: "This code was compiled for x86_64 architecture" on 64-bit x86 machines. */
#elif C_ARCHITECTURE_I386
printf("This code was compiled for %s architecture.", C_ARCHITECTURE); /* Will print: "This code was compiled for i386 architecture" on 32-bit x86 machines. */
#endif
}The non-obscure architectures c_predefined.h will recognise by default are:
The capitalised macro-name part (for C_ARCHITECTURE_<macro-name part>) |
The human-readable string (given by C_ARCHITECTURE) |
|---|---|
X86_64 |
"x86_64" |
ARM64 |
"ARM64" |
I386 |
"i386" |
ARM |
"ARM" |
MIPS |
"MIPS" |
POWERPC |
"PowerPC" |
SPARC |
"SPARC" |
Tons more are recognised by defining C_PREDEFINED_OBSCURE_ARCHITECTURES 1 before including "c_predefined.h" (see Options for more info).
The convention for getting compilers is basically identical to architectures just with "COMPILER" replacing "ARCHITECTURE" in in macro names. To find out if a specific compiler is in use
#if C_COMPILER_<compiler name in all caps> == 1
or simply
#if define(C_COMPILER_<compiler name in all caps>) /* or #ifdef C_COMPILER_<capitalised compiler name> */
either of the above will be true if the specified compiler is the primary compiler in use.
Additionally, a human-readable and properly-cased string for whatever the current compiler is, is defined for C_COMPILER.
Note, c_predefined.h uses whatever the most-specific applicable compiler name is so, for example, it will use C_COMPILER_CLANG over simply C_COMPILER_LLVM in clang even though Clang is built on top of LLVM (with C_COMPILER_LLVM being used for other, unrecognised, LLVM-based compilers.)
Full example:
#include "c_predefined.h"
#include <stdio.h>
int main(int argc, char *argv[]){
#if C_COMPILER_CLANG
printf("This code was compiled with %s.", C_COMPILER); /* Will print: "This code was compiled with Clang" on Clang. */
#elif C_COMPILER_LLVMj
printf("This code was compiled with %s.", C_COMPILER); /* Will print: "This code was compiled with LLVM" on un-named, LLVM-based compilers. */
#endif
}The non-obscure compilers c_predefined.h will recognise by default are:
The capitalised macro-name part (for C_COMPILER_<macro-name part>) |
The human-readable string (given by C_COMPILER) |
|---|---|
MINGW |
"MinGW" |
MICROSOFT_VISUAL |
"Microsoft Visual C++" |
IBM_XL |
"IBM XL C/C++" |
INTEL |
"Intel C/C++" |
HP_ACPP |
"HP aC++" |
PORTLAND_GROUP |
"Portland Group" |
CLANG |
"Clang" |
GCC |
"GCC" |
ORACLE_PRO |
"Oracle Pro C" |
SUN_PRO |
"Sun Pro" |
LLVM |
"LLVM" |
HP_ANSI |
"HP ANSI C" |
TINYC |
"Tiny C" |
METROWERKS_CODEWARRIOR |
"Metrowerks CodeWarrior" |
BORLAND |
"Borland C++" |
Tons more are recognised by defining C_PREDEFINED_OBSCURE_COMPILERS 1 before including "c_predefined.h" (see Options for more info).
The convention for getting systems is basically identical to architectures and compilers just with "SYSTEM" replacing "ARCHITECTURE/COMPILER" in in macro names. To find out if a specific system is in use
#if C_SYSTEM_<system name in all caps> == 1
or simply
#if define(C_SYSTEM_<system name in all caps>) /* or #ifdef C_SYSTEM_<capitalised system name> */
either of the above will be true if the specified system is the primary system in use.
Additionally, a human-readable and properly-cased string for whatever the current system is, is defined for C_SYSTEM.
Note, c_predefined.h uses whatever the most-specific applicable system name is so, for example, C_SYSTEM_GNU_LINUX will be preferred over simply C_SYSTEM_LINUX OR C_SYSTEM_UNIX where appropriate.
Full example:
#include "c_predefined.h"
#include <stdio.h>
int main(int argc, char *argv[]){
#if C_SYSTEM_CYGWIN
printf("This code was compiled for %s.", C_SYSTEM); /* Will print: "This code was compiled for Cygwin" on Cygwin. */
#elif C_SYSTEM_LLVM
printf("This code was compiled for %s.", C_SYSTEM); /* Will print: "This code was compiled for Windows CE" on Windows CE based systems. */
#endif
}The non-obscure systems c_predefined.h will recognise by default are:
The capitalised macro-name part (for C_SYSTEM_<macro-name part>) |
The human-readable string (given by C_SYSTEM) |
|---|---|
CYGWIN |
"Cygwin" |
WINDOWSCE |
"Windows CE" |
WINDOWS |
"Windows" |
APPLE |
"Apple (mac/i/tv)OS" |
ANDROID |
"Android" |
OPENBSD |
"OpenBSD" |
NETBSD |
"NetBSD" |
GNU_HURD |
"GNU/Hurd" |
SOLARIS |
"Sun Solaris" |
FREEBSD_KERNEL |
"GNU/FreeBSD Kernel" |
FREEBSD |
"FreeBSD" |
MSDOS |
"MSDOS" |
MACINTOSH |
"Macintosh" |
LYNX |
"Lynx" |
MINIX |
"Minix" |
QNX |
"QNX" |
BSDI |
"BSD/OS" |
GNU_LINUX |
"GNU/Linux" |
BSD |
"BSD" |
GNU |
"GNU" |
LINUX |
"Linux" |
UNIX |
"Unix" |
Tons more are recognised by defining C_PREDEFINED_OBSCURE_SYSTEMS 1 before including "c_predefined.h" (see Options for more info).
Additionally, c_predefined.h recognises several language standards for both C and C++ compilers:
C_STANDARD_C90C_STANDARD_C94C_STANDARD_C99C_STANDARD_C11C_STANDARD_HOSTEDC_STANDARD_CPP98C_STANDARD_CPP11C_STANDARD_CPP14C_STANDARD_CLIC_STANDARD_EMBEDDED
will all evaluate to 1 if the corresponding standard is being implemented. Unlike the architecture/compiler/system constants specified above, standards are cumulative so, for example, it's possible for both C_STANDARD_C94 and C_STANDARD_C99 to evaluate to 1 at the same time.
c_predefined.h can also wrap Unix standards specified <unistd.h> if C_PREDEFINED_UNIX_STANDARDS is defined to equal 1 before including "c_predefined.h"; obviously this options should only be used on POSIX-compliant unix-based systems. I may implement an automatic check for if this should be enabled in future updates.
If C_PREDEFINED_HELPFUL_MACROS is defined to 1 before including "c_predefined.h", c_predefined.h can also wrap some other, less-ubiquitous, helpful macros under the C_STANDARD moniker as follows:
C_STANDARD_ELFC_STANDARD_CHAR_UNSIGNEDC_STANDARD_WCHAR_UNSIGNEDC_STANDARD_BYTE_SIZEC_STANDARD_LITTLE_ENDIANC_STANDARD_BIG_ENDIANC_STANDARD_PDP_ENDIANC_STANDARD_FLOAT_WORD_ORDER_LITTLE_ENDIANC_STANDARD_FLOAT_WORD_ORDER_BIG_ENDIANC_STANDARD_OBJECTIVECC_STANDARD_ASSEMBLYC_STANDARD_STRICT_ANSIC_STANDARD_DEPRECATEDC_STANDARD_EXCEPTIONSC_STANDARD_64BIT_LONG_INT_AND_POINTER
The sheer breadth of macros c_predefined.h can check for and wrap as needed can be adjust by defining any number of the following macros to a value of 1 before include "c_predefined.h":
| Macro name | Effect |
|---|---|
C_PREDEFINED_OBSCURE_ARCHITECTURES |
Adds tons of macros for vintage and obscure architectures to be checked against, and wrapped if found. |
C_PREDEFINED_OBSCURE_COMPILERS |
Adds tons of macros for vintage and obscure compilers to be checked against, and wrapped if found. |
C_PREDEFINED_OBSCURE_SYSTEMS |
Adds tons of macros for vintage and obscure systems to be checked against, and wrapped if found. |
C_PREDEFINED_UNIX_STANDARDS |
Wraps macros from <unistd.h> with the same C_STANDARD_<language-standard code> convention as other standards. |
C_PREDEFINED_HELPFUL_MACROS |
Adds additional, helpful but less common macros to C_STANDARD_<macro name> |
Example:
#define C_PREDEFINED_OBSCURE_ARCHITECTURES 1
#define C_PREDEFINED_OBSCURE_COMPILERS 1
#define C_PREDEFINED_OBSCURE_SYSTEMS 1
#define C_PREDEFINED_UNIX_STANDARDS 1
#define C_PREDEFINED_HELPFUL_MACROS 1
#include "c_predefined.h"Changes are tracked in CHANGES.md.
Any pull request to add additional predefined macros are welcome, just be sure to provide attribution to the official documentation for the architecture/compiler/system which recognises them.
MIT ©2017-2021 Anadian
SEE LICENSE IN LICENSE