Intermediate · The preprocessor, multi-file programs and make · topic 37 of 60 · 20 min
Conditional compilation and include guards
Explanation
Keeping or removing code
#define DEBUG 1
#if DEBUG
printf("x = %d\n", x); /* compiled only when DEBUG is non-zero */
#endif
#ifdef USE_SMS /* true if USE_SMS is defined at all */
send_sms(phone, text);
#else
send_email(email, text);
#endifDefining flags from the command line
gcc -DDEBUG prog.c -o prog # like #define DEBUG 1
gcc -DMAX_USERS=500 prog.c -o prog # like #define MAX_USERS 500
gcc -DNDEBUG -O2 prog.c -o prog # NDEBUG turns off assert() (module 11)Platform checks
#if defined(_WIN32)
#include <windows.h>
#define PATH_SEP '\\'
#elif defined(__linux__) || defined(__APPLE__)
#include <unistd.h>
#define PATH_SEP '/'
#else
#error "Unsupported platform" /* stops compilation with a message */
#endifCompilers predefine macros that describe the target: _WIN32, __linux__, __APPLE__, __x86_64__, __arm__, and __STDC_VERSION__ (for example 201710L for C17). Use them sparingly; keep platform-specific code in small, separate files where possible.
Checking the C standard version
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 202311L
/* C23: bool, true and false are keywords */
#else
#include <stdbool.h>
#endif
_Static_assert(sizeof(int) >= 4, "this code assumes at least 32-bit int"); /* C11 compile-time check */Include guards
If two headers both include "money.h", and a .c file includes both, money.h would be pasted twice, and its struct definitions would be duplicated, which is a compile error ("redefinition of struct Money"). An include guard makes the second inclusion empty.
/* money.h */
#ifndef MONEY_H
#define MONEY_H
typedef struct { long paise; } Money;
Money money_add(Money a, Money b);
#endif /* MONEY_H *//* the shorter, non-standard but widely supported alternative */
#pragma once
typedef struct { long paise; } Money;Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Conditional compilation and include guards · 1/6
In this lesson you will include or exclude code before compilation.
Prefer a video by a teacher? Find free videos on “c conditional compilation ifdef include guards pragma once” on YouTube ↗
In real life: Debug logging that costs nothing in production
Firmware for a medical weighing scale prints detailed sensor values during development but must be as small and fast as possible in the shipped device. A DEBUG_LOG macro expands to a printf in debug builds and to nothing at all in release builds.
#ifdef DEBUG
#define DEBUG_LOG(...) fprintf(stderr, __VA_ARGS__)
#else
#define DEBUG_LOG(...) ((void) 0)
#endif
DEBUG_LOG("raw=%d filtered=%d\n", raw, filtered); /* gone entirely unless built with -DDEBUG */Practice (0/3 done)
What does this print when compiled WITHOUT -DPRO? #ifdef PRO puts("Pro"); #else puts("Free"); #endif
Why do headers need include guards?
Create config.h with an include guard and a #ifdef DEBUG section that defines a LOG macro (printing) or an empty LOG macro otherwise. Include config.h twice from main.c (directly and through another header) to prove the guard works. Build once with -DDEBUG and once without, and compare the output.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Splitting a program into filesThe preprocessor, multi-file programs and make · same module
- Building with makeThe preprocessor, multi-file programs and make · same module
- Functions: declare, define, call and returnC++ Programming (modern C++ and DSA) · Decisions, loops and functions
- Decisions with if and elseJavaScript Programming (language in depth) · Strings, decisions and loops
- Protecting spanning tree: PortFast, BPDU Guard, Root Guard and Loop GuardComputer Networking (CCNA level) · Spanning Tree and EtherChannel
- If sentences: zero and first conditionalSpoken English: Zero to Fluent · Polite and useful grammar
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
What does gcc -DVERBOSE do?
Answer: Defines the macro VERBOSE (as 1)
Like #define VERBOSE 1.
What does #error do?
Answer: Stops compilation with a message
Used for unsupported configurations.
Is #pragma once part of the C standard?
Answer: No, but most compilers support it
Include guards are the standard way.
Which macro is predefined when compiling for Windows?
Answer: _WIN32
_WIN32 is defined for 32- and 64-bit Windows targets.
What is the difference between #include "x.h" and #include <x.h>?Related
Answer: "" searches the project's folders first; <> searches the system include folders
Use "" for your own headers.
When does macro replacement happen?Related
Which stage expands #include and #define?Related
What does #pragma once at the top of a header do?Related
Answer: Stops the header from being included more than once in the same .cpp file
It is an include guard: repeated #includes of that header are skipped.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 3 more topics in “The preprocessor, multi-file programs and make” before its exam: Splitting a program into files, Building with make, Libraries: static and shared.
- Module 8 exam: Preprocessor, multi-file programs and make · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
- Then the next module, Bits, undefined behaviour and safety. 60 topics left in the course before the final exam.