Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Learn Pitfalls and Best Practices | Conditional compilation
C Preprocessing

Swipe to show menu

book
Pitfalls and Best Practices

Condition Directives in Header Files

To avoid multiple inclusions of the same header file (which can cause redefinition errors for macros or functions), you should protect your header files using:

python

The HEADER_H macro in this case acts as a flag. Initially, it doesn't exist, meaning the file has not been included yet.

After the first #define HEADER_H, the flag is set. From that point on, every time the compiler encounters #ifndef HEADER_H, it detects the flag and skips the content until #endif.

It's a form of protection from double inclusion.

Essentially, the preprocessor checks during the code processing whether the flag already exists.

If the flag exists, it skips the content, if it doesn't exist, it includes the content and sets the flag.

This is a very simple but extremely important technique that prevents a lot of issues in large projects.

Forgotten End

A common mistake is forgetting to close a conditional block with #endif, especially when multiple nested #if, #ifdef, or #ifndef directives are used.

Properly closing each conditional block with #endif is crucial for ensuring the code is processed correctly.

Macro Soup

Macros can be a powerful tool for optimizing or flexibly compiling your program, but their excessive use can lead to a "macro mess" β€” a situation where the code becomes difficult to understand and debug.

c

main

copy
123456789101112131415161718192021222324
#include <stdio.h> #define STEP_1 2 #define STEP_2 3 #define STEP_3 5 #define STEP_4 8 #define PART_1 (STEP_1 * STEP_2) #define PART_2 (PART_1 + STEP_3) #define PART_3 (PART_2 - STEP_4) #define CONCAT_1 "?" #define CONCAT_2 "?" #define CONCAT_3 "?" #define TEMP_1 (PART_3 * STEP_2) #define TEMP_2 (TEMP_1 / STEP_1) #define FINAL_RESULT (TEMP_2 + PART_3) // 4 + 3 = 7 #if FINAL_RESULT == 7 #define FINAL_OUTPUT CONCAT_1 CONCAT_2 CONCAT_3 #else #define FINAL_OUTPUT "ERROR" #endif int main() { printf("The final result is: %s\n", FINAL_OUTPUT); return 0; }

Single Location for Macros

What does this mean?

Macros should be defined in a single place, usually in a header file or a dedicated configuration file.
This helps avoid duplication and ensures centralized management.

Why is this important?

When macros are defined in one place, they can be easily changed or updated without having to review every function or file where they are used.

This reduces the chance of errors caused by forgetting to update a macro value in multiple places.

Let’s take the program from the previous lesson, where we configured communication protocols.

We’ll move all the macros into a single header file called config.

c

main

h

config

copy
12345678910
#include <stdio.h> #include "config.h" int main() { LOG(PROTOCOL_DEBUG); printf(PROTOCOL_MESSAGE); printf(ENCRYPTION_MESSAGE); printf(VERSION_MESSAGE); return 0; }

Descriptive Names

Why it matters:

Clear, descriptive macro names make the code easier to read, understand, and maintain. They reduce the risk of errors and simplify collaboration on projects.

Bad example (unclear, abstract names):

c

main

copy
12345678910111213141516
#include <stdio.h> #define A 1 #define B 0 #define C 3 int main() { if (A) { printf("Feature enabled.\n"); } if (B) { printf("Debug mode active.\n"); } printf("Protocol version: %d\n", C); return 0; }

Good example (descriptive names):

c

main

copy
12345678910111213141516
#include <stdio.h> #define ENABLE_FEATURE 1 #define DEBUG_MODE 0 #define PROTOCOL_VERSION 3 int main() { if (ENABLE_FEATURE) { printf("Feature enabled.\n"); } if (DEBUG_MODE) { printf("Debug mode active.\n"); } printf("Protocol version: %d\n", PROTOCOL_VERSION); return 0; }
Switch to desktopSwitch to desktop for real-world practiceContinue from where you are using one of the options below
Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 3. ChapterΒ 4
We're sorry to hear that something went wrong. What happened?

Ask AI

expand
ChatGPT

Ask anything or try one of the suggested questions to begin our chat

book
Pitfalls and Best Practices

Condition Directives in Header Files

To avoid multiple inclusions of the same header file (which can cause redefinition errors for macros or functions), you should protect your header files using:

python

The HEADER_H macro in this case acts as a flag. Initially, it doesn't exist, meaning the file has not been included yet.

After the first #define HEADER_H, the flag is set. From that point on, every time the compiler encounters #ifndef HEADER_H, it detects the flag and skips the content until #endif.

It's a form of protection from double inclusion.

Essentially, the preprocessor checks during the code processing whether the flag already exists.

If the flag exists, it skips the content, if it doesn't exist, it includes the content and sets the flag.

This is a very simple but extremely important technique that prevents a lot of issues in large projects.

Forgotten End

A common mistake is forgetting to close a conditional block with #endif, especially when multiple nested #if, #ifdef, or #ifndef directives are used.

Properly closing each conditional block with #endif is crucial for ensuring the code is processed correctly.

Macro Soup

Macros can be a powerful tool for optimizing or flexibly compiling your program, but their excessive use can lead to a "macro mess" β€” a situation where the code becomes difficult to understand and debug.

c

main

copy
123456789101112131415161718192021222324
#include <stdio.h> #define STEP_1 2 #define STEP_2 3 #define STEP_3 5 #define STEP_4 8 #define PART_1 (STEP_1 * STEP_2) #define PART_2 (PART_1 + STEP_3) #define PART_3 (PART_2 - STEP_4) #define CONCAT_1 "?" #define CONCAT_2 "?" #define CONCAT_3 "?" #define TEMP_1 (PART_3 * STEP_2) #define TEMP_2 (TEMP_1 / STEP_1) #define FINAL_RESULT (TEMP_2 + PART_3) // 4 + 3 = 7 #if FINAL_RESULT == 7 #define FINAL_OUTPUT CONCAT_1 CONCAT_2 CONCAT_3 #else #define FINAL_OUTPUT "ERROR" #endif int main() { printf("The final result is: %s\n", FINAL_OUTPUT); return 0; }

Single Location for Macros

What does this mean?

Macros should be defined in a single place, usually in a header file or a dedicated configuration file.
This helps avoid duplication and ensures centralized management.

Why is this important?

When macros are defined in one place, they can be easily changed or updated without having to review every function or file where they are used.

This reduces the chance of errors caused by forgetting to update a macro value in multiple places.

Let’s take the program from the previous lesson, where we configured communication protocols.

We’ll move all the macros into a single header file called config.

c

main

h

config

copy
12345678910
#include <stdio.h> #include "config.h" int main() { LOG(PROTOCOL_DEBUG); printf(PROTOCOL_MESSAGE); printf(ENCRYPTION_MESSAGE); printf(VERSION_MESSAGE); return 0; }

Descriptive Names

Why it matters:

Clear, descriptive macro names make the code easier to read, understand, and maintain. They reduce the risk of errors and simplify collaboration on projects.

Bad example (unclear, abstract names):

c

main

copy
12345678910111213141516
#include <stdio.h> #define A 1 #define B 0 #define C 3 int main() { if (A) { printf("Feature enabled.\n"); } if (B) { printf("Debug mode active.\n"); } printf("Protocol version: %d\n", C); return 0; }

Good example (descriptive names):

c

main

copy
12345678910111213141516
#include <stdio.h> #define ENABLE_FEATURE 1 #define DEBUG_MODE 0 #define PROTOCOL_VERSION 3 int main() { if (ENABLE_FEATURE) { printf("Feature enabled.\n"); } if (DEBUG_MODE) { printf("Debug mode active.\n"); } printf("Protocol version: %d\n", PROTOCOL_VERSION); return 0; }
Switch to desktopSwitch to desktop for real-world practiceContinue from where you are using one of the options below
Everything was clear?

How can we improve it?

Thanks for your feedback!

SectionΒ 3. ChapterΒ 4
Switch to desktopSwitch to desktop for real-world practiceContinue from where you are using one of the options below
We're sorry to hear that something went wrong. What happened?
some-alt