//the preprocessor chooses the code before compilation:
//the other branch is not compiled at all
#define DEBUG 1
#define VERSION 3
#if DEBUG
const char *mode = "debug";
#else
const char *mode = "release";
#endif
//mode is "debug"
//#if computes integer expressions, #elif is its "else if"
#if VERSION >= 3
int features = 30;
#elif VERSION == 2
int features = 20;
#else
int features = 10;
#endif
//features is 30
//#error stops the build with a message,
//here only when the condition is true
#if VERSION < 2
#error "VERSION 2 or newer is needed"
#endif
//#ifdef and #ifndef only ask whether the name is defined;
//defined() does the same inside #if,
//C23 adds #elifdef and #elifndef
#ifdef LOGGING
bool logging = true;
#else
bool logging = false;
#endif
//logging is false
//the compiler defines names of its own: this is how the code
//picks the platform (the sandbox runs Linux)
#if defined(_WIN32)
const char *platform = "Windows";
#elif defined(__APPLE__)
const char *platform = "macOS";
#elif defined(__linux__)
const char *platform = "Linux";
#else
const char *platform = "unknown";
#endif
//platform is "Linux"
//#if 0 turns off a piece of code, even one with comments inside
#if 0
printf("this line is not compiled\n"); /* not even seen */
#endif
printf("mode is %s\n", mode);
printf("features is %d\n", features);
printf("logging is %s\n", logging ? "true" : "false");
printf("platform is %s\n", platform);