c
examples
examples.c🔧c
/**
* =============================================================================
* Macros and Definitions in C - Examples
* =============================================================================
*
* This file demonstrates various types of macros and their applications in C
* programming. Each example is self-contained and well-documented.
*
* Compile: gcc -Wall -Wextra -std=c99 -o examples examples.c
* Run: ./examples
*
* Topics Covered:
* 1. Object-like Macros
* 2. Function-like Macros
* 3. Stringification Operator
* 4. Token Pasting Operator
* 5. Variadic Macros
* 6. Advanced Macro Techniques
* =============================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stddef.h> // For offsetof
// =============================================================================
// Example 1: Basic Object-like Macros
// =============================================================================
#define PI 3.14159265359
#define E 2.71828182845
#define MAX_BUFFER_SIZE 1024
#define PROGRAM_NAME "Macro Examples"
#define VERSION_MAJOR 1
#define VERSION_MINOR 0
#define VERSION_PATCH 0
void example_object_macros(void) {
printf("\n=== Example 1: Object-like Macros ===\n");
printf("Program: %s\n", PROGRAM_NAME);
printf("Version: %d.%d.%d\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH);
printf("\n");
// Using numeric constants
double radius = 5.0;
double area = PI * radius * radius;
double circumference = 2 * PI * radius;
printf("Circle with radius %.2f:\n", radius);
printf(" Area: %.4f\n", area);
printf(" Circumference: %.4f\n", circumference);
printf("\n");
// Buffer allocation using macro
char buffer[MAX_BUFFER_SIZE];
snprintf(buffer, sizeof(buffer), "Buffer size is %d bytes", MAX_BUFFER_SIZE);
printf("%s\n", buffer);
}
// =============================================================================
// Example 2: Multi-line and Expression Macros
// =============================================================================
#define DOUBLE_BUFFER_SIZE (MAX_BUFFER_SIZE * 2)
#define HALF_BUFFER_SIZE (MAX_BUFFER_SIZE / 2)
#define HEADER_TEXT "====================================\n" \
" PROGRAM OUTPUT REPORT \n" \
"====================================\n"
#define FOOTER_TEXT "====================================\n" \
" END OF REPORT \n" \
"===================================="
void example_multiline_macros(void) {
printf("\n=== Example 2: Multi-line and Expression Macros ===\n");
printf(HEADER_TEXT);
printf("Single buffer size: %d\n", MAX_BUFFER_SIZE);
printf("Double buffer size: %d\n", DOUBLE_BUFFER_SIZE);
printf("Half buffer size: %d\n", HALF_BUFFER_SIZE);
printf(FOOTER_TEXT);
printf("\n");
}
// =============================================================================
// Example 3: Basic Function-like Macros
// =============================================================================
#define SQUARE(x) ((x) * (x))
#define CUBE(x) ((x) * (x) * (x))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define CLAMP(x, lo, hi) (MIN(MAX((x), (lo)), (hi)))
void example_function_macros(void) {
printf("\n=== Example 3: Basic Function-like Macros ===\n");
int a = 5, b = 8;
printf("a = %d, b = %d\n", a, b);
printf("SQUARE(%d) = %d\n", a, SQUARE(a));
printf("CUBE(%d) = %d\n", a, CUBE(a));
printf("MAX(%d, %d) = %d\n", a, b, MAX(a, b));
printf("MIN(%d, %d) = %d\n", a, b, MIN(a, b));
printf("\n");
int x = -15;
printf("x = %d\n", x);
printf("ABS(%d) = %d\n", x, ABS(x));
printf("\n");
int value = 150;
int low = 0, high = 100;
printf("CLAMP(%d, %d, %d) = %d\n", value, low, high, CLAMP(value, low, high));
value = -50;
printf("CLAMP(%d, %d, %d) = %d\n", value, low, high, CLAMP(value, low, high));
value = 50;
printf("CLAMP(%d, %d, %d) = %d\n", value, low, high, CLAMP(value, low, high));
}
// =============================================================================
// Example 4: Importance of Parentheses
// =============================================================================
// Wrong way - missing parentheses
#define BAD_DOUBLE(x) x * 2
#define BAD_SQUARE(x) x * x
// Right way - with parentheses
#define GOOD_DOUBLE(x) ((x) * 2)
#define GOOD_SQUARE(x) ((x) * (x))
void example_parentheses_importance(void) {
printf("\n=== Example 4: Importance of Parentheses ===\n");
int result;
// Demonstrate the problem with missing parentheses
printf("Testing with expression (3 + 4):\n");
result = BAD_DOUBLE(3 + 4);
printf(" BAD_DOUBLE(3 + 4) = %d (3 + 4 * 2 = 11, wrong!)\n", result);
result = GOOD_DOUBLE(3 + 4);
printf(" GOOD_DOUBLE(3 + 4) = %d (((3 + 4)) * 2 = 14, correct!)\n", result);
printf("\n");
printf("Testing with expression (2 + 3):\n");
result = BAD_SQUARE(2 + 3);
printf(" BAD_SQUARE(2 + 3) = %d (2 + 3 * 2 + 3 = 11, wrong!)\n", result);
result = GOOD_SQUARE(2 + 3);
printf(" GOOD_SQUARE(2 + 3) = %d (((2 + 3)) * ((2 + 3)) = 25, correct!)\n", result);
}
// =============================================================================
// Example 5: Multi-statement Macros with do-while
// =============================================================================
// Wrong way - multiple statements without do-while
#define BAD_SWAP(a, b) { int temp = a; a = b; b = temp; }
// Right way - using do-while(0)
#define SWAP_INT(a, b) do { \
int temp = (a); \
(a) = (b); \
(b) = temp; \
} while(0)
#define PRINT_ARRAY(arr, size) do { \
printf("["); \
for (int _i = 0; _i < (size); _i++) { \
if (_i > 0) printf(", "); \
printf("%d", (arr)[_i]); \
} \
printf("]\n"); \
} while(0)
void example_multistatement_macros(void) {
printf("\n=== Example 5: Multi-statement Macros ===\n");
int x = 10, y = 20;
printf("Before swap: x = %d, y = %d\n", x, y);
SWAP_INT(x, y);
printf("After swap: x = %d, y = %d\n", x, y);
printf("\n");
int arr[] = {1, 2, 3, 4, 5};
int size = sizeof(arr) / sizeof(arr[0]);
printf("Array: ");
PRINT_ARRAY(arr, size);
}
// =============================================================================
// Example 6: Stringification Operator (#)
// =============================================================================
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define PRINT_VAR(var) printf(#var " = %d\n", var)
#define PRINT_EXPR(expr) printf(#expr " = %d\n", (expr))
#define VERSION 100
#define BUILD_NUMBER 2024
void example_stringification(void) {
printf("\n=== Example 6: Stringification Operator (#) ===\n");
// Basic stringification
printf("STRINGIFY(Hello World) = %s\n", STRINGIFY(Hello World));
printf("STRINGIFY(3.14159) = %s\n", STRINGIFY(3.14159));
printf("\n");
// Two-level stringification
printf("STRINGIFY(VERSION) = %s (just the name)\n", STRINGIFY(VERSION));
printf("TOSTRING(VERSION) = %s (the value)\n", TOSTRING(VERSION));
printf("TOSTRING(BUILD_NUMBER) = %s\n", TOSTRING(BUILD_NUMBER));
printf("\n");
// Practical use: printing variable names with values
int count = 42;
int total = 100;
PRINT_VAR(count);
PRINT_VAR(total);
printf("\n");
// Printing expressions
int a = 5, b = 7;
PRINT_EXPR(a + b);
PRINT_EXPR(a * b);
PRINT_EXPR(a + b * 2);
}
// =============================================================================
// Example 7: Token Pasting Operator (##)
// =============================================================================
#define CONCAT(a, b) a ## b
#define MAKE_VAR(name, num) name ## num
// Create getter and setter functions
#define DECLARE_ACCESSORS(type, name) \
static type _##name; \
static type get_##name(void) { return _##name; } \
static void set_##name(type value) { _##name = value; }
// Generate print functions for different types
#define DEFINE_PRINT(type, fmt) \
void print_##type(type value) { \
printf(#type ": " fmt "\n", value); \
}
DECLARE_ACCESSORS(int, score)
DECLARE_ACCESSORS(float, rate)
DEFINE_PRINT(int, "%d")
DEFINE_PRINT(float, "%f")
DEFINE_PRINT(double, "%lf")
void example_token_pasting(void) {
printf("\n=== Example 7: Token Pasting Operator (##) ===\n");
// Basic concatenation
int CONCAT(my, Var) = 100;
int MAKE_VAR(count, 1) = 10;
int MAKE_VAR(count, 2) = 20;
printf("myVar = %d\n", myVar);
printf("count1 = %d\n", count1);
printf("count2 = %d\n", count2);
printf("\n");
// Using generated accessor functions
set_score(95);
set_rate(3.14f);
printf("Score: %d\n", get_score());
printf("Rate: %.2f\n", get_rate());
printf("\n");
// Using generated print functions
print_int(42);
print_float(3.14159f);
print_double(2.71828);
}
// =============================================================================
// Example 8: Variadic Macros
// =============================================================================
#define SIMPLE_PRINT(...) printf(__VA_ARGS__)
#define LOG_INFO(fmt, ...) printf("[INFO] " fmt "\n", ##__VA_ARGS__)
#define LOG_WARN(fmt, ...) printf("[WARN] " fmt "\n", ##__VA_ARGS__)
#define LOG_ERROR(fmt, ...) printf("[ERROR] " fmt "\n", ##__VA_ARGS__)
#define DEBUG_LOG(fmt, ...) \
printf("[DEBUG %s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
void example_variadic_macros(void) {
printf("\n=== Example 8: Variadic Macros ===\n");
// Simple variadic macro
SIMPLE_PRINT("Hello, World!\n");
SIMPLE_PRINT("Value: %d\n", 42);
SIMPLE_PRINT("Sum of %d and %d is %d\n", 10, 20, 30);
printf("\n");
// Logging macros
LOG_INFO("Application started");
LOG_INFO("Processing file: %s", "data.txt");
LOG_WARN("Low memory: %d%% available", 15);
LOG_ERROR("Failed to open file: %s (error %d)", "missing.txt", 404);
printf("\n");
// Debug logging with file and line
DEBUG_LOG("Starting processing");
DEBUG_LOG("Processing item %d", 42);
}
// =============================================================================
// Example 9: Array and Memory Macros
// =============================================================================
#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
#define SAFE_FREE(ptr) do { \
if ((ptr) != NULL) { \
free(ptr); \
(ptr) = NULL; \
} \
} while(0)
#define SAFE_ALLOC(ptr, type, count) do { \
(ptr) = (type *)malloc(sizeof(type) * (count)); \
if ((ptr) == NULL) { \
fprintf(stderr, "Memory allocation failed at %s:%d\n", __FILE__, __LINE__); \
} \
} while(0)
#define ZERO_ARRAY(arr) memset((arr), 0, sizeof(arr))
#define FOREACH_INDEX(i, arr) \
for (size_t i = 0; i < ARRAY_SIZE(arr); i++)
void example_array_memory_macros(void) {
printf("\n=== Example 9: Array and Memory Macros ===\n");
// ARRAY_SIZE usage
int numbers[] = {10, 20, 30, 40, 50};
char name[] = "Hello";
double values[] = {1.1, 2.2, 3.3};
printf("Size of numbers array: %zu\n", ARRAY_SIZE(numbers));
printf("Size of name array: %zu (including null)\n", ARRAY_SIZE(name));
printf("Size of values array: %zu\n", ARRAY_SIZE(values));
printf("\n");
// FOREACH_INDEX usage
printf("Numbers: ");
FOREACH_INDEX(i, numbers) {
printf("%d ", numbers[i]);
}
printf("\n\n");
// SAFE_ALLOC and SAFE_FREE
int *dynamic_arr = NULL;
SAFE_ALLOC(dynamic_arr, int, 5);
if (dynamic_arr) {
for (int i = 0; i < 5; i++) {
dynamic_arr[i] = (i + 1) * 10;
}
printf("Dynamic array: ");
for (int i = 0; i < 5; i++) {
printf("%d ", dynamic_arr[i]);
}
printf("\n");
SAFE_FREE(dynamic_arr);
printf("After SAFE_FREE, pointer is: %p\n", (void *)dynamic_arr);
}
printf("\n");
// ZERO_ARRAY usage
int buffer[5] = {1, 2, 3, 4, 5};
printf("Before ZERO_ARRAY: ");
for (int i = 0; i < 5; i++) printf("%d ", buffer[i]);
printf("\n");
ZERO_ARRAY(buffer);
printf("After ZERO_ARRAY: ");
for (int i = 0; i < 5; i++) printf("%d ", buffer[i]);
printf("\n");
}
// =============================================================================
// Example 10: Bit Manipulation Macros
// =============================================================================
#define SET_BIT(n, bit) ((n) | (1 << (bit)))
#define CLEAR_BIT(n, bit) ((n) & ~(1 << (bit)))
#define TOGGLE_BIT(n, bit) ((n) ^ (1 << (bit)))
#define CHECK_BIT(n, bit) (((n) >> (bit)) & 1)
#define GET_BIT(n, bit) CHECK_BIT(n, bit)
#define SET_BITS(n, mask) ((n) | (mask))
#define CLEAR_BITS(n, mask) ((n) & ~(mask))
#define TOGGLE_BITS(n, mask) ((n) ^ (mask))
#define PRINT_BINARY(n) do { \
printf(#n " = 0b"); \
for (int _i = 7; _i >= 0; _i--) { \
printf("%d", ((n) >> _i) & 1); \
} \
printf(" (%d)\n", n); \
} while(0)
void example_bit_macros(void) {
printf("\n=== Example 10: Bit Manipulation Macros ===\n");
unsigned char value = 0b00001010; // 10 in decimal
PRINT_BINARY(value);
printf("\n");
// SET_BIT
unsigned char set = SET_BIT(value, 0); // Set bit 0
printf("After SET_BIT(value, 0):\n");
PRINT_BINARY(set);
// CLEAR_BIT
unsigned char clear = CLEAR_BIT(value, 1); // Clear bit 1
printf("\nAfter CLEAR_BIT(value, 1):\n");
PRINT_BINARY(clear);
// TOGGLE_BIT
unsigned char toggle = TOGGLE_BIT(value, 3); // Toggle bit 3
printf("\nAfter TOGGLE_BIT(value, 3):\n");
PRINT_BINARY(toggle);
// CHECK_BIT
printf("\nChecking bits in value (0b00001010):\n");
for (int i = 7; i >= 0; i--) {
printf(" Bit %d: %d\n", i, CHECK_BIT(value, i));
}
}
// =============================================================================
// Example 11: Predefined Macros
// =============================================================================
void example_predefined_macros(void) {
printf("\n=== Example 11: Predefined Macros ===\n");
// Standard predefined macros
printf("File: %s\n", __FILE__);
printf("Line: %d\n", __LINE__);
printf("Date: %s\n", __DATE__);
printf("Time: %s\n", __TIME__);
printf("Function: %s\n", __func__); // C99
printf("\n");
// Standard version
#ifdef __STDC__
printf("ANSI C compliant: Yes\n");
#else
printf("ANSI C compliant: No\n");
#endif
#ifdef __STDC_VERSION__
printf("C Standard Version: %ld\n", __STDC_VERSION__);
#if __STDC_VERSION__ >= 201112L
printf(" (C11 or later)\n");
#elif __STDC_VERSION__ >= 199901L
printf(" (C99)\n");
#endif
#endif
printf("\n");
// Compiler-specific macros
#ifdef __GNUC__
printf("GCC Version: %d.%d.%d\n", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__);
#endif
#ifdef __clang__
printf("Clang compiler detected\n");
#endif
}
// =============================================================================
// Example 12: Debug and Assert Macros
// =============================================================================
// Enable debug mode for this example
#define DEBUG_MODE 1
#if DEBUG_MODE
#define DBG_PRINT(fmt, ...) \
fprintf(stderr, "[DEBUG %s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
#define DBG_ASSERT(condition) do { \
if (!(condition)) { \
fprintf(stderr, "ASSERTION FAILED: %s\n", #condition); \
fprintf(stderr, " File: %s\n", __FILE__); \
fprintf(stderr, " Line: %d\n", __LINE__); \
fprintf(stderr, " Function: %s\n", __func__); \
} \
} while(0)
#define DBG_TRACE() \
fprintf(stderr, "[TRACE] Entering %s()\n", __func__)
#else
#define DBG_PRINT(fmt, ...) ((void)0)
#define DBG_ASSERT(condition) ((void)0)
#define DBG_TRACE() ((void)0)
#endif
// Custom assert that doesn't abort
#define SOFT_ASSERT(condition, msg) do { \
if (!(condition)) { \
fprintf(stderr, "Warning: %s (%s)\n", msg, #condition); \
} \
} while(0)
void helper_function(int value) {
DBG_TRACE();
DBG_PRINT("Processing value: %d", value);
DBG_ASSERT(value > 0);
}
void example_debug_macros(void) {
printf("\n=== Example 12: Debug and Assert Macros ===\n");
DBG_TRACE();
int x = 10;
DBG_PRINT("Starting with x = %d", x);
helper_function(x);
helper_function(-5); // Will trigger assertion
printf("\n");
// Soft assertions
int score = 150;
SOFT_ASSERT(score >= 0 && score <= 100, "Score out of valid range");
char *name = NULL;
SOFT_ASSERT(name != NULL, "Name pointer is null");
}
// =============================================================================
// Example 13: Type-Generic Macros (C11 _Generic)
// =============================================================================
#if __STDC_VERSION__ >= 201112L
#define TYPE_NAME(x) _Generic((x), \
int: "int", \
float: "float", \
double: "double", \
char *: "char pointer", \
int *: "int pointer", \
default: "unknown")
#define PRINT_VALUE(x) _Generic((x), \
int: printf("int: %d\n", x), \
float: printf("float: %f\n", x), \
double: printf("double: %lf\n", x), \
char *: printf("string: %s\n", x), \
default: printf("unknown type\n"))
void example_generic_macros(void) {
printf("\n=== Example 13: Type-Generic Macros (C11) ===\n");
int i = 42;
float f = 3.14f;
double d = 2.71828;
char *s = "Hello";
printf("Type of i: %s\n", TYPE_NAME(i));
printf("Type of f: %s\n", TYPE_NAME(f));
printf("Type of d: %s\n", TYPE_NAME(d));
printf("Type of s: %s\n", TYPE_NAME(s));
printf("\n");
PRINT_VALUE(i);
PRINT_VALUE(f);
PRINT_VALUE(d);
PRINT_VALUE(s);
}
#else
void example_generic_macros(void) {
printf("\n=== Example 13: Type-Generic Macros ===\n");
printf("(C11 _Generic not available in this compiler)\n");
}
#endif
// =============================================================================
// Example 14: X-Macro Technique
// =============================================================================
// Define colors using X-macro
#define COLOR_LIST \
X(COLOR_RED, "Red", 0xFF0000) \
X(COLOR_GREEN, "Green", 0x00FF00) \
X(COLOR_BLUE, "Blue", 0x0000FF) \
X(COLOR_YELLOW, "Yellow", 0xFFFF00) \
X(COLOR_CYAN, "Cyan", 0x00FFFF) \
X(COLOR_WHITE, "White", 0xFFFFFF) \
X(COLOR_BLACK, "Black", 0x000000)
// Generate enum
#define X(name, str, val) name,
typedef enum { COLOR_LIST COLOR_COUNT } Color;
#undef X
// Generate string array
#define X(name, str, val) [name] = str,
static const char *color_names[] = { COLOR_LIST };
#undef X
// Generate hex value array
#define X(name, str, val) [name] = val,
static const int color_values[] = { COLOR_LIST };
#undef X
// Function to get color info
void print_color_info(Color c) {
if (c < COLOR_COUNT) {
printf("Color: %-8s Hex: 0x%06X\n", color_names[c], color_values[c]);
}
}
void example_xmacro(void) {
printf("\n=== Example 14: X-Macro Technique ===\n");
printf("Total colors defined: %d\n\n", COLOR_COUNT);
printf("All colors:\n");
for (Color c = 0; c < COLOR_COUNT; c++) {
print_color_info(c);
}
printf("\n");
// Using the enum values
Color myColor = COLOR_BLUE;
printf("My color is %s (0x%06X)\n", color_names[myColor], color_values[myColor]);
}
// =============================================================================
// Example 15: Container and Struct Macros
// =============================================================================
// Get pointer to struct containing this member
#define container_of(ptr, type, member) \
((type *)((char *)(ptr) - offsetof(type, member)))
// Define a simple linked list node
typedef struct ListNode {
int data;
struct ListNode *next;
} ListNode;
// Wrapper structure containing a ListNode
typedef struct {
char name[32];
int id;
ListNode node; // Embedded node
} Person;
// Initialize a structure with default values
#define INIT_PERSON(p, n, i) do { \
strncpy((p)->name, (n), sizeof((p)->name) - 1); \
(p)->name[sizeof((p)->name) - 1] = '\0'; \
(p)->id = (i); \
(p)->node.data = 0; \
(p)->node.next = NULL; \
} while(0)
void example_container_macros(void) {
printf("\n=== Example 15: Container and Struct Macros ===\n");
Person alice;
INIT_PERSON(&alice, "Alice", 1001);
printf("Person: %s (ID: %d)\n", alice.name, alice.id);
printf("Address of alice: %p\n", (void *)&alice);
printf("Address of alice.node: %p\n", (void *)&alice.node);
// Recover Person pointer from node pointer
ListNode *node_ptr = &alice.node;
Person *recovered = container_of(node_ptr, Person, node);
printf("Recovered from node: %s (ID: %d)\n", recovered->name, recovered->id);
printf("container_of result: %p\n", (void *)recovered);
printf("Same as original: %s\n", (recovered == &alice) ? "Yes" : "No");
}
// =============================================================================
// Example 16: State Machine Macros
// =============================================================================
// State machine state definitions
#define STATE_LIST \
STATE(IDLE, "Idle") \
STATE(RUNNING, "Running") \
STATE(PAUSED, "Paused") \
STATE(STOPPED, "Stopped")
// Generate state enum
#define STATE(name, str) STATE_##name,
typedef enum { STATE_LIST STATE_COUNT } MachineState;
#undef STATE
// Generate state name strings
#define STATE(name, str) [STATE_##name] = str,
static const char *state_names[] = { STATE_LIST };
#undef STATE
// State transition macro
#define TRANSITION(machine, new_state) do { \
printf("Transition: %s -> %s\n", \
state_names[(machine)], state_names[(new_state)]); \
(machine) = (new_state); \
} while(0)
void example_state_machine(void) {
printf("\n=== Example 16: State Machine Macros ===\n");
MachineState machine = STATE_IDLE;
printf("Initial state: %s\n\n", state_names[machine]);
TRANSITION(machine, STATE_RUNNING);
TRANSITION(machine, STATE_PAUSED);
TRANSITION(machine, STATE_RUNNING);
TRANSITION(machine, STATE_STOPPED);
printf("\nFinal state: %s\n", state_names[machine]);
}
// =============================================================================
// Example 17: Build Configuration Macros
// =============================================================================
// Simulated build configuration
#define CONFIG_DEBUG 1
#define CONFIG_LOG_LEVEL 2 // 0=none, 1=error, 2=warn, 3=info, 4=debug
#define CONFIG_FEATURE_A 1
#define CONFIG_FEATURE_B 0
#define CONFIG_MAX_CONNECTIONS 100
// Feature toggle macros
#if CONFIG_FEATURE_A
#define feature_a_enabled() (1)
#define FEATURE_A_CODE(code) code
#else
#define feature_a_enabled() (0)
#define FEATURE_A_CODE(code)
#endif
#if CONFIG_FEATURE_B
#define feature_b_enabled() (1)
#define FEATURE_B_CODE(code) code
#else
#define feature_b_enabled() (0)
#define FEATURE_B_CODE(code)
#endif
// Log level macros
#if CONFIG_LOG_LEVEL >= 1
#define LOG_ERR(msg) printf("[ERR] %s\n", msg)
#else
#define LOG_ERR(msg)
#endif
#if CONFIG_LOG_LEVEL >= 2
#define LOG_WRN(msg) printf("[WARN] %s\n", msg)
#else
#define LOG_WRN(msg)
#endif
#if CONFIG_LOG_LEVEL >= 3
#define LOG_INF(msg) printf("[INFO] %s\n", msg)
#else
#define LOG_INF(msg)
#endif
#if CONFIG_LOG_LEVEL >= 4
#define LOG_DBG(msg) printf("[DBG] %s\n", msg)
#else
#define LOG_DBG(msg)
#endif
void example_build_config(void) {
printf("\n=== Example 17: Build Configuration Macros ===\n");
printf("Configuration:\n");
printf(" Debug mode: %s\n", CONFIG_DEBUG ? "enabled" : "disabled");
printf(" Log level: %d\n", CONFIG_LOG_LEVEL);
printf(" Feature A: %s\n", feature_a_enabled() ? "enabled" : "disabled");
printf(" Feature B: %s\n", feature_b_enabled() ? "enabled" : "disabled");
printf(" Max connections: %d\n", CONFIG_MAX_CONNECTIONS);
printf("\n");
// Log level demonstration
LOG_ERR("This is an error");
LOG_WRN("This is a warning");
LOG_INF("This is info"); // Won't show (level 2 < 3)
LOG_DBG("This is debug"); // Won't show (level 2 < 4)
printf("\n");
// Feature toggle demonstration
FEATURE_A_CODE(printf("Feature A code is included\n");)
FEATURE_B_CODE(printf("Feature B code is included\n");) // Won't compile in
if (feature_a_enabled()) {
printf("Running Feature A logic...\n");
}
if (feature_b_enabled()) {
printf("Running Feature B logic...\n"); // Won't execute
}
}
// =============================================================================
// Main Function
// =============================================================================
int main(void) {
printf("============================================================\n");
printf(" MACROS AND DEFINITIONS IN C - EXAMPLES \n");
printf("============================================================\n");
example_object_macros();
example_multiline_macros();
example_function_macros();
example_parentheses_importance();
example_multistatement_macros();
example_stringification();
example_token_pasting();
example_variadic_macros();
example_array_memory_macros();
example_bit_macros();
example_predefined_macros();
example_debug_macros();
example_generic_macros();
example_xmacro();
example_container_macros();
example_state_machine();
example_build_config();
printf("\n============================================================\n");
printf(" ALL EXAMPLES COMPLETED \n");
printf("============================================================\n");
return 0;
}