StudyLover
  • Home
  • Study Zone
  • Profiles
  • Typing Tutor
  • B Tree
  • Contact us
  • Sign in
StudyLover Advanced C Preprocessor Techniques 馃З
Download
  1. C Programming
  2. Unit 2: Program Control Flow & Logic
The C Preprocessor 馃摐 : C Programming: Conditional Statements 鈿栵笍
Unit 2: Program Control Flow & Logic

Mastering the C preprocessor is a form of meta-programming. You can write code that writes code, enabling patterns that are impossible with C syntax alone.

1. The Stringification (#) and Token-Pasting (##) Operators

These two operators work only within #define macros and provide powerful text manipulation capabilities.

a) The Stringification Operator (#)

The # operator takes a macro parameter and turns it into a string literal without expanding the parameter's definition.

路聽聽聽聽聽聽聽聽 Purpose: Useful for creating debugging macros that can print both a variable's name and its value.

Example:

C

#include <stdio.h>

聽
#define PRINT_VAR(var) printf(#var " = %d\n", var)

聽
int main() {

聽聽聽 int counter = 100;

聽聽聽 

聽聽聽聽// The preprocessor expands this to:

聽聽聽 // printf("counter" " = %d\n", counter);

聽聽聽 // which the compiler treats as: printf("counter = %d\n", counter);

聽聽聽 PRINT_VAR(counter);

聽聽聽 

聽聽聽聽return 0;

}

b) The Token-Pasting Operator (##)

The ## operator concatenates two separate tokens into a single new token.

路聽聽聽聽聽聽聽聽 Purpose: Used to create unique variable or function names programmatically within a macro.

Example:

C

#include <stdio.h>

聽
#define DEFINE_HANDLER(name) void handle_##name(void) { \

聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽 printf("Handling " #name " event.\n"); \

聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽 }

聽
// This macro call expands to:

// void handle_error(void) { printf("Handling error event.\n"); }

DEFINE_HANDLER(error);

聽
// This macro call expands to:

// void handle_success(void) { printf("Handling success event.\n"); }

DEFINE_HANDLER(success);

聽
int main() {

聽聽聽 handle_error();

聽聽聽 handle_success();

聽聽聽 return 0;

}


聽

2. Variadic Macros (C99 and later)

Variadic macros can accept a variable number of arguments, similar to functions like printf.

路聽聽聽聽聽聽聽聽 Syntax: ... is used to represent the variable arguments, and the special identifier __VA_ARGS__ is used to access them in the macro's body.

路聽聽聽聽聽聽聽聽 Purpose: Essential for creating generic logging or wrapper functions.

Example: A custom debug logging macro

C

#include <stdio.h>

聽
// __FILE__ and __LINE__ are standard predefined macros

#define DEBUG_LOG(format, ...) fprintf(stderr, "[DEBUG] %s:%d: " format, \

聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽 __FILE__, __LINE__, __VA_ARGS__)

聽
int main() {

聽聽聽 int user_id = 123;

聽聽聽 char *status = "success";

聽
聽聽聽 // This expands to a single fprintf call with all the arguments

聽聽聽 DEBUG_LOG("User login status: %s, ID: %d\n", status, user_id);

聽聽聽 

聽聽聽聽return 0;

}


聽

3. The do-while(0) Trick for Safe Macros

When a macro contains multiple statements, it can break the logic of if-else blocks if it's not used with curly braces. The standard professional solution is to wrap the macro's body in a do { ... } while(0) loop.

路聽聽聽聽聽聽聽聽 Why it works: This construct ensures the entire macro body is parsed as a single, complete statement that correctly consumes the trailing semicolon.

Example:

C

// UNSAFE MACRO

#define FREE_MEM(p) free(p); p = NULL;

聽
// SAFE MACRO

#define SAFE_FREE(p) do { free(p); p = NULL; } while(0)

聽
int main() {

聽聽聽 int *p1 = malloc(sizeof(int));

聽聽聽 int *p2 = malloc(sizeof(int));

聽聽聽 

聽聽聽聽if (p1 == NULL)

聽聽聽聽聽聽聽 FREE_MEM(p2); // Problem! Expands to: if (...) free(p2);; p2=NULL;

聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽 // The p2=NULL is OUTSIDE the if.

聽聽聽 

聽聽聽聽if (p2 == NULL)

聽聽聽聽聽聽聽 SAFE_FREE(p1); // Correct. Expands to: if (...) do { ... } while(0);

聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽聽 // The entire block is a single statement.

聽聽聽 return 0;

}


聽

4. X-Macros for Code Generation

This is an advanced technique for maintaining parallel lists of related items (e.g., enums and their string representations) without redundancy. The list is defined in one place, and a macro is used to "expand" that list for different purposes.

Example: Generating enums and a corresponding string table

C

#include <stdio.h>

聽
// 1. Define the list of items using an X-Macro

#define COLOR_LIST \

聽聽聽 X(RED, "Red") \

聽聽聽 X(GREEN, "Green") \

聽聽聽 X(BLUE, "Blue")

聽
// 2. Expand the list to create an enum

typedef enum {

#define X(name, str) C_##name,

聽 聽聽COLOR_LIST

#undef X

} Color;

聽
// 3. Expand the same list again to create a string table

const char *ColorStrings[] = {

#define X(name, str) str,

聽聽聽 COLOR_LIST

#undef X

};

聽
int main() {

聽聽聽 Color myColor = C_GREEN;

聽聽聽 

聽聽聽聽// The enum and string array are guaranteed to be in sync

聽聽聽 printf("My color is %s\n", ColorStrings[myColor]); // Prints "My color is Green"

聽聽聽 

聽聽聽聽return 0;

}

聽

聽

Conditional statements, also known as branching statements, allow a program to make decisions and execute different blocks of code based on whether a specific condition is true or false.


The C Preprocessor 馃摐 C Programming: Conditional Statements 鈿栵笍
Our Products & Services
  • Home
Connect with us
  • Contact us
  • +91 82955 87844
  • Rk6yadav@gmail.com

StudyLover - About us

The Best knowledge for Best people.

Copyright © StudyLover
Powered by Odoo - Create a free website