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

Contenuti del Corso

C Preprocessing

C Preprocessing

1. Introduction to Preprocessing
2. Macros
3. Conditional compilation

book
Pitfalls and Best Practices

Using #ifndef 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 functions as a flag that:

  • Initially doesn't exist: meaning the file has not been included yet;
  • After the first #define HEADER_H: the flag gets set;


Every subsequent time when the compiler encounters #ifndef HEADER_H it detects the flag and skips all the content until #endif.

It's a form of protection from double inclusion.

Basically, the preprocessor checks during the code processing:

  • whether the flag already exists;
  • if it exists — it skips;
  • 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 #endif

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 code easier to read, understand, and maintain.

They reduce the risk of errors and simplify teamwork on projects.

Bad example (unclear, abstract names):

c

main

copy
1234567891011121314151617
#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
1234567891011121314151617
#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 desktopCambia al desktop per esercitarti nel mondo realeContinua da dove ti trovi utilizzando una delle opzioni seguenti
Tutto è chiaro?

Come possiamo migliorarlo?

Grazie per i tuoi commenti!

Sezione 3. Capitolo 4
toggle bottom row

book
Pitfalls and Best Practices

Using #ifndef 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 functions as a flag that:

  • Initially doesn't exist: meaning the file has not been included yet;
  • After the first #define HEADER_H: the flag gets set;


Every subsequent time when the compiler encounters #ifndef HEADER_H it detects the flag and skips all the content until #endif.

It's a form of protection from double inclusion.

Basically, the preprocessor checks during the code processing:

  • whether the flag already exists;
  • if it exists — it skips;
  • 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 #endif

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 code easier to read, understand, and maintain.

They reduce the risk of errors and simplify teamwork on projects.

Bad example (unclear, abstract names):

c

main

copy
1234567891011121314151617
#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
1234567891011121314151617
#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 desktopCambia al desktop per esercitarti nel mondo realeContinua da dove ti trovi utilizzando una delle opzioni seguenti
Tutto è chiaro?

Come possiamo migliorarlo?

Grazie per i tuoi commenti!

Sezione 3. Capitolo 4
Switch to desktopCambia al desktop per esercitarti nel mondo realeContinua da dove ti trovi utilizzando una delle opzioni seguenti
Siamo spiacenti che qualcosa sia andato storto. Cosa è successo?
some-alt