c

examples

examples.c🔧
/**
 * =============================================================================
 * Header Files and Include Guards in C - Examples
 * =============================================================================
 * 
 * This file demonstrates header file concepts and include guards.
 * For a complete example, we'll simulate a multi-file project in a single file.
 * 
 * In a real project, these would be separate .h and .c files.
 * 
 * Compile: gcc -Wall -Wextra -std=c99 -o examples examples.c -lm
 * Run: ./examples
 * 
 * Topics Covered:
 * 1. Include guard pattern
 * 2. Header file organization
 * 3. Forward declarations
 * 4. Opaque pointers
 * 5. Inline functions in headers
 * 6. C++ compatibility
 * =============================================================================
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>

// =============================================================================
// Example 1: Basic Include Guard Pattern
// =============================================================================

/*
 * This is how you would write a header file with include guards:
 * 
 * File: math_utils.h
 */

// --- BEGIN math_utils.h ---
#ifndef MATH_UTILS_H
#define MATH_UTILS_H

// Constants
#define MATH_PI 3.14159265359
#define MATH_E  2.71828182845

// Type definitions
typedef struct {
    double x;
    double y;
} Point2D;

typedef struct {
    double x;
    double y;
    double z;
} Point3D;

// Function prototypes
double math_distance_2d(Point2D a, Point2D b);
double math_distance_3d(Point3D a, Point3D b);
double math_area_circle(double radius);
double math_area_triangle(double base, double height);

#endif /* MATH_UTILS_H */
// --- END math_utils.h ---

/*
 * File: math_utils.c (implementation)
 */
// #include "math_utils.h"  // Would include the header

double math_distance_2d(Point2D a, Point2D b) {
    double dx = b.x - a.x;
    double dy = b.y - a.y;
    return sqrt(dx * dx + dy * dy);
}

double math_distance_3d(Point3D a, Point3D b) {
    double dx = b.x - a.x;
    double dy = b.y - a.y;
    double dz = b.z - a.z;
    return sqrt(dx * dx + dy * dy + dz * dz);
}

double math_area_circle(double radius) {
    return MATH_PI * radius * radius;
}

double math_area_triangle(double base, double height) {
    return 0.5 * base * height;
}

void example_include_guards(void) {
    printf("\n=== Example 1: Basic Include Guard Pattern ===\n");
    
    Point2D p1 = {0.0, 0.0};
    Point2D p2 = {3.0, 4.0};
    
    printf("Point 1: (%.1f, %.1f)\n", p1.x, p1.y);
    printf("Point 2: (%.1f, %.1f)\n", p2.x, p2.y);
    printf("Distance: %.2f\n", math_distance_2d(p1, p2));
    printf("\n");
    
    double radius = 5.0;
    printf("Circle with radius %.1f:\n", radius);
    printf("  Area: %.4f\n", math_area_circle(radius));
    printf("  (using PI = %.10f)\n", MATH_PI);
}

// =============================================================================
// Example 2: Multiple Inclusion Prevention Demo
// =============================================================================

/*
 * Without include guards, including a header twice would cause errors.
 * 
 * Simulating the scenario:
 * - a.h defines struct Color
 * - b.h includes a.h and uses Color
 * - main.c includes both a.h and b.h
 * 
 * Without guards: Error - Color redefined!
 * With guards: Works correctly - Color defined only once
 */

// --- BEGIN color.h (with guards) ---
#ifndef COLOR_H
#define COLOR_H

typedef struct {
    uint8_t r, g, b, a;
} Color;

#define COLOR_RED   ((Color){255, 0, 0, 255})
#define COLOR_GREEN ((Color){0, 255, 0, 255})
#define COLOR_BLUE  ((Color){0, 0, 255, 255})
#define COLOR_WHITE ((Color){255, 255, 255, 255})
#define COLOR_BLACK ((Color){0, 0, 0, 255})

Color color_blend(Color c1, Color c2);
void color_print(Color c);

#endif /* COLOR_H */
// --- END color.h ---

// --- BEGIN graphics.h ---
#ifndef GRAPHICS_H
#define GRAPHICS_H

// Including color.h again is safe due to include guards
// #include "color.h"  // This would be here in real code

void graphics_draw_pixel(int x, int y, Color c);
void graphics_fill_rect(int x, int y, int w, int h, Color c);

#endif /* GRAPHICS_H */
// --- END graphics.h ---

Color color_blend(Color c1, Color c2) {
    Color result;
    result.r = (c1.r + c2.r) / 2;
    result.g = (c1.g + c2.g) / 2;
    result.b = (c1.b + c2.b) / 2;
    result.a = (c1.a + c2.a) / 2;
    return result;
}

void color_print(Color c) {
    printf("Color(R=%d, G=%d, B=%d, A=%d)", c.r, c.g, c.b, c.a);
}

void graphics_draw_pixel(int x, int y, Color c) {
    printf("Drawing pixel at (%d, %d) with ", x, y);
    color_print(c);
    printf("\n");
}

void graphics_fill_rect(int x, int y, int w, int h, Color c) {
    printf("Filling rect at (%d, %d) size %dx%d with ", x, y, w, h);
    color_print(c);
    printf("\n");
}

void example_multiple_inclusion(void) {
    printf("\n=== Example 2: Multiple Inclusion Prevention ===\n");
    
    Color red = COLOR_RED;
    Color blue = COLOR_BLUE;
    
    printf("Red: ");
    color_print(red);
    printf("\nBlue: ");
    color_print(blue);
    printf("\n");
    
    Color purple = color_blend(red, blue);
    printf("Blended (purple): ");
    color_print(purple);
    printf("\n\n");
    
    graphics_draw_pixel(10, 20, red);
    graphics_fill_rect(0, 0, 100, 50, blue);
}

// =============================================================================
// Example 3: Forward Declarations
// =============================================================================

/*
 * Forward declarations let you declare a type without fully defining it.
 * This is useful for reducing header dependencies and handling circular references.
 */

// --- BEGIN node.h ---
#ifndef NODE_H
#define NODE_H

// Forward declaration - Tree is defined in tree.h
struct Tree;

typedef struct Node {
    int value;
    struct Node *left;
    struct Node *right;
    struct Tree *owner;  // Only pointer, no full definition needed
} Node;

Node* node_create(int value);
void node_destroy(Node *node);
void node_print(Node *node);

#endif /* NODE_H */
// --- END node.h ---

// --- BEGIN tree.h ---
#ifndef TREE_H
#define TREE_H

// Now we include node.h because we need the full Node definition
// #include "node.h"

typedef struct Tree {
    Node *root;
    int size;
    char name[32];
} Tree;

Tree* tree_create(const char *name);
void tree_destroy(Tree *tree);
void tree_insert(Tree *tree, int value);
void tree_print(Tree *tree);

#endif /* TREE_H */
// --- END tree.h ---

// Implementations
Node* node_create(int value) {
    Node *node = malloc(sizeof(Node));
    if (node) {
        node->value = value;
        node->left = NULL;
        node->right = NULL;
        node->owner = NULL;
    }
    return node;
}

void node_destroy(Node *node) {
    if (node) {
        node_destroy(node->left);
        node_destroy(node->right);
        free(node);
    }
}

void node_print(Node *node) {
    if (node) {
        node_print(node->left);
        printf("%d ", node->value);
        node_print(node->right);
    }
}

Tree* tree_create(const char *name) {
    Tree *tree = malloc(sizeof(Tree));
    if (tree) {
        tree->root = NULL;
        tree->size = 0;
        strncpy(tree->name, name, sizeof(tree->name) - 1);
        tree->name[sizeof(tree->name) - 1] = '\0';
    }
    return tree;
}

void tree_destroy(Tree *tree) {
    if (tree) {
        node_destroy(tree->root);
        free(tree);
    }
}

static void tree_insert_node(Tree *tree, Node **node, int value) {
    if (*node == NULL) {
        *node = node_create(value);
        if (*node) {
            (*node)->owner = tree;
            tree->size++;
        }
    } else if (value < (*node)->value) {
        tree_insert_node(tree, &(*node)->left, value);
    } else {
        tree_insert_node(tree, &(*node)->right, value);
    }
}

void tree_insert(Tree *tree, int value) {
    if (tree) {
        tree_insert_node(tree, &tree->root, value);
    }
}

void tree_print(Tree *tree) {
    if (tree) {
        printf("Tree '%s' (size=%d): ", tree->name, tree->size);
        node_print(tree->root);
        printf("\n");
    }
}

void example_forward_declarations(void) {
    printf("\n=== Example 3: Forward Declarations ===\n");
    
    Tree *tree = tree_create("MyTree");
    
    tree_insert(tree, 50);
    tree_insert(tree, 30);
    tree_insert(tree, 70);
    tree_insert(tree, 20);
    tree_insert(tree, 40);
    tree_insert(tree, 60);
    tree_insert(tree, 80);
    
    tree_print(tree);
    
    tree_destroy(tree);
}

// =============================================================================
// Example 4: Opaque Pointers (Pimpl Pattern)
// =============================================================================

/*
 * Opaque pointers hide implementation details from users.
 * The structure is declared but not defined in the header.
 */

// --- BEGIN database.h (public API) ---
#ifndef DATABASE_H
#define DATABASE_H

#include <stdbool.h>

// Opaque type - implementation is hidden
typedef struct Database Database;

// Result type for operations
typedef enum {
    DB_OK = 0,
    DB_ERROR_OPEN,
    DB_ERROR_CLOSE,
    DB_ERROR_QUERY,
    DB_ERROR_NOT_FOUND
} DatabaseResult;

// Public API
Database* database_open(const char *filename);
void database_close(Database *db);
DatabaseResult database_query(Database *db, const char *query);
bool database_is_connected(const Database *db);
const char* database_error_string(DatabaseResult result);

#endif /* DATABASE_H */
// --- END database.h ---

// --- BEGIN database.c (private implementation) ---
// #include "database.h"

// Private structure definition - users can't access internal fields
struct Database {
    char filename[256];
    bool connected;
    int query_count;
    char last_error[128];
    // ... more private fields
};

Database* database_open(const char *filename) {
    Database *db = malloc(sizeof(Database));
    if (db) {
        strncpy(db->filename, filename, sizeof(db->filename) - 1);
        db->filename[sizeof(db->filename) - 1] = '\0';
        db->connected = true;
        db->query_count = 0;
        db->last_error[0] = '\0';
        printf("[DB] Opened database: %s\n", filename);
    }
    return db;
}

void database_close(Database *db) {
    if (db) {
        printf("[DB] Closed database: %s (queries: %d)\n", 
               db->filename, db->query_count);
        db->connected = false;
        free(db);
    }
}

DatabaseResult database_query(Database *db, const char *query) {
    if (!db || !db->connected) {
        return DB_ERROR_QUERY;
    }
    db->query_count++;
    printf("[DB] Query %d: %s\n", db->query_count, query);
    return DB_OK;
}

bool database_is_connected(const Database *db) {
    return db && db->connected;
}

const char* database_error_string(DatabaseResult result) {
    switch (result) {
        case DB_OK: return "Success";
        case DB_ERROR_OPEN: return "Failed to open database";
        case DB_ERROR_CLOSE: return "Failed to close database";
        case DB_ERROR_QUERY: return "Query failed";
        case DB_ERROR_NOT_FOUND: return "Record not found";
        default: return "Unknown error";
    }
}
// --- END database.c ---

void example_opaque_pointers(void) {
    printf("\n=== Example 4: Opaque Pointers (Pimpl Pattern) ===\n");
    
    Database *db = database_open("users.db");
    
    if (database_is_connected(db)) {
        printf("Database connected: Yes\n\n");
        
        DatabaseResult result;
        result = database_query(db, "SELECT * FROM users");
        printf("Result: %s\n", database_error_string(result));
        
        result = database_query(db, "INSERT INTO users VALUES (1, 'Alice')");
        printf("Result: %s\n", database_error_string(result));
    }
    
    printf("\n");
    database_close(db);
    
    printf("\nNote: Users cannot access db->filename or other internals!\n");
    printf("This provides encapsulation and allows internal changes\n");
    printf("without breaking the public API.\n");
}

// =============================================================================
// Example 5: Inline Functions in Headers
// =============================================================================

/*
 * Small utility functions can be defined inline in headers.
 * They should be marked 'static inline' to avoid multiple definition errors.
 */

// --- BEGIN inline_utils.h ---
#ifndef INLINE_UTILS_H
#define INLINE_UTILS_H

#include <stdlib.h>
#include <string.h>

// Inline min/max functions
static inline int inline_min(int a, int b) {
    return (a < b) ? a : b;
}

static inline int inline_max(int a, int b) {
    return (a > b) ? a : b;
}

static inline int inline_clamp(int value, int min_val, int max_val) {
    return inline_min(inline_max(value, min_val), max_val);
}

// Inline string utilities
static inline bool inline_str_empty(const char *str) {
    return str == NULL || *str == '\0';
}

static inline size_t inline_str_len(const char *str) {
    return str ? strlen(str) : 0;
}

// Safe memory operations
static inline void* inline_safe_malloc(size_t size) {
    void *ptr = malloc(size);
    if (ptr == NULL && size > 0) {
        fprintf(stderr, "Memory allocation failed!\n");
    }
    return ptr;
}

static inline void inline_safe_free(void **ptr) {
    if (ptr && *ptr) {
        free(*ptr);
        *ptr = NULL;
    }
}

// Bit manipulation
static inline bool inline_bit_get(uint32_t value, int bit) {
    return (value >> bit) & 1;
}

static inline uint32_t inline_bit_set(uint32_t value, int bit) {
    return value | (1 << bit);
}

static inline uint32_t inline_bit_clear(uint32_t value, int bit) {
    return value & ~(1 << bit);
}

#endif /* INLINE_UTILS_H */
// --- END inline_utils.h ---

void example_inline_functions(void) {
    printf("\n=== Example 5: Inline Functions in Headers ===\n");
    
    // min/max/clamp
    printf("inline_min(5, 3) = %d\n", inline_min(5, 3));
    printf("inline_max(5, 3) = %d\n", inline_max(5, 3));
    printf("inline_clamp(150, 0, 100) = %d\n", inline_clamp(150, 0, 100));
    printf("\n");
    
    // String utilities
    const char *test1 = "Hello";
    const char *test2 = "";
    const char *test3 = NULL;
    
    printf("inline_str_empty(\"%s\") = %s\n", test1, inline_str_empty(test1) ? "true" : "false");
    printf("inline_str_empty(\"\") = %s\n", inline_str_empty(test2) ? "true" : "false");
    printf("inline_str_empty(NULL) = %s\n", inline_str_empty(test3) ? "true" : "false");
    printf("inline_str_len(\"%s\") = %zu\n", test1, inline_str_len(test1));
    printf("\n");
    
    // Bit manipulation
    uint32_t value = 0b00001010;  // 10 in decimal
    printf("Original value: %u (0b%08b)\n", value, value);
    printf("Bit 1 set: %s\n", inline_bit_get(value, 1) ? "yes" : "no");
    printf("Bit 2 set: %s\n", inline_bit_get(value, 2) ? "yes" : "no");
    printf("After setting bit 0: %u\n", inline_bit_set(value, 0));
    printf("After clearing bit 1: %u\n", inline_bit_clear(value, 1));
}

// =============================================================================
// Example 6: C++ Compatibility
// =============================================================================

/*
 * For headers that might be used from C++, wrap declarations in extern "C".
 * This prevents C++ name mangling.
 */

// --- BEGIN c_api.h ---
#ifndef C_API_H
#define C_API_H

#ifdef __cplusplus
extern "C" {
#endif

// API version
#define C_API_VERSION_MAJOR 1
#define C_API_VERSION_MINOR 0

// Types
typedef struct {
    int x, y;
} C_API_Point;

typedef struct {
    int width, height;
} C_API_Size;

typedef struct {
    C_API_Point origin;
    C_API_Size size;
} C_API_Rect;

// Functions - these can be called from C++
C_API_Rect c_api_rect_create(int x, int y, int w, int h);
int c_api_rect_area(C_API_Rect rect);
bool c_api_rect_contains_point(C_API_Rect rect, C_API_Point point);
C_API_Rect c_api_rect_intersection(C_API_Rect a, C_API_Rect b);

#ifdef __cplusplus
}
#endif

#endif /* C_API_H */
// --- END c_api.h ---

// Implementation
C_API_Rect c_api_rect_create(int x, int y, int w, int h) {
    C_API_Rect rect = {{x, y}, {w, h}};
    return rect;
}

int c_api_rect_area(C_API_Rect rect) {
    return rect.size.width * rect.size.height;
}

bool c_api_rect_contains_point(C_API_Rect rect, C_API_Point point) {
    return point.x >= rect.origin.x && 
           point.x < rect.origin.x + rect.size.width &&
           point.y >= rect.origin.y && 
           point.y < rect.origin.y + rect.size.height;
}

C_API_Rect c_api_rect_intersection(C_API_Rect a, C_API_Rect b) {
    int x1 = inline_max(a.origin.x, b.origin.x);
    int y1 = inline_max(a.origin.y, b.origin.y);
    int x2 = inline_min(a.origin.x + a.size.width, b.origin.x + b.size.width);
    int y2 = inline_min(a.origin.y + a.size.height, b.origin.y + b.size.height);
    
    C_API_Rect result = {{0, 0}, {0, 0}};
    if (x2 > x1 && y2 > y1) {
        result.origin.x = x1;
        result.origin.y = y1;
        result.size.width = x2 - x1;
        result.size.height = y2 - y1;
    }
    return result;
}

void example_cpp_compatibility(void) {
    printf("\n=== Example 6: C++ Compatibility ===\n");
    
    C_API_Rect rect1 = c_api_rect_create(0, 0, 100, 80);
    C_API_Rect rect2 = c_api_rect_create(50, 40, 100, 80);
    
    printf("Rectangle 1: origin=(%d,%d), size=%dx%d, area=%d\n",
           rect1.origin.x, rect1.origin.y,
           rect1.size.width, rect1.size.height,
           c_api_rect_area(rect1));
    
    printf("Rectangle 2: origin=(%d,%d), size=%dx%d, area=%d\n",
           rect2.origin.x, rect2.origin.y,
           rect2.size.width, rect2.size.height,
           c_api_rect_area(rect2));
    
    C_API_Point point = {75, 60};
    printf("\nPoint (%d, %d):\n", point.x, point.y);
    printf("  In rect1: %s\n", c_api_rect_contains_point(rect1, point) ? "Yes" : "No");
    printf("  In rect2: %s\n", c_api_rect_contains_point(rect2, point) ? "Yes" : "No");
    
    C_API_Rect intersection = c_api_rect_intersection(rect1, rect2);
    printf("\nIntersection: origin=(%d,%d), size=%dx%d\n",
           intersection.origin.x, intersection.origin.y,
           intersection.size.width, intersection.size.height);
    
    printf("\nNote: With 'extern \"C\"', these functions can be called\n");
    printf("directly from C++ code without name mangling issues.\n");
}

// =============================================================================
// Example 7: Header Organization Patterns
// =============================================================================

/*
 * Demonstrating common header organization patterns.
 */

// --- Pattern 1: Configuration Header ---
// config.h
#ifndef CONFIG_H
#define CONFIG_H

// Build configuration
#ifndef DEBUG
    #define DEBUG 0
#endif

// Version info
#define APP_VERSION_MAJOR 2
#define APP_VERSION_MINOR 5
#define APP_VERSION_PATCH 1
#define APP_VERSION_STRING "2.5.1"

// Feature flags
#define FEATURE_LOGGING 1
#define FEATURE_NETWORKING 0

// Limits
#define MAX_BUFFER_SIZE 4096
#define MAX_FILENAME_LEN 256

#endif /* CONFIG_H */

// --- Pattern 2: Types Header ---
// types.h
#ifndef TYPES_H_EXAMPLE
#define TYPES_H_EXAMPLE

// Basic type aliases
typedef uint8_t  u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t   i8;
typedef int16_t  i16;
typedef int32_t  i32;
typedef int64_t  i64;
typedef float    f32;
typedef double   f64;

// Common result type
typedef enum {
    RESULT_OK = 0,
    RESULT_ERROR = -1,
    RESULT_NOT_FOUND = -2,
    RESULT_INVALID = -3
} Result;

#endif /* TYPES_H_EXAMPLE */

// --- Pattern 3: Error Handling Header ---
// error.h
#ifndef ERROR_H
#define ERROR_H

typedef enum {
    ERR_NONE = 0,
    ERR_MEMORY,
    ERR_IO,
    ERR_INVALID_ARG,
    ERR_NOT_FOUND,
    ERR_PERMISSION,
    ERR_TIMEOUT,
    ERR_UNKNOWN
} ErrorCode;

typedef struct {
    ErrorCode code;
    char message[256];
    const char *file;
    int line;
} Error;

#define ERROR_INIT ((Error){ERR_NONE, "", __FILE__, __LINE__})

static inline void error_set(Error *err, ErrorCode code, const char *msg) {
    if (err) {
        err->code = code;
        strncpy(err->message, msg, sizeof(err->message) - 1);
        err->message[sizeof(err->message) - 1] = '\0';
    }
}

static inline bool error_ok(const Error *err) {
    return err == NULL || err->code == ERR_NONE;
}

#endif /* ERROR_H */

void example_header_organization(void) {
    printf("\n=== Example 7: Header Organization Patterns ===\n");
    
    printf("Configuration (from config.h):\n");
    printf("  Version: %s\n", APP_VERSION_STRING);
    printf("  Debug: %s\n", DEBUG ? "Yes" : "No");
    printf("  Max buffer: %d\n", MAX_BUFFER_SIZE);
    printf("\n");
    
    printf("Type aliases (from types.h):\n");
    printf("  sizeof(u8) = %zu\n", sizeof(u8));
    printf("  sizeof(u32) = %zu\n", sizeof(u32));
    printf("  sizeof(f32) = %zu\n", sizeof(f32));
    printf("\n");
    
    printf("Error handling (from error.h):\n");
    Error err = ERROR_INIT;
    printf("  Initial error state: %s\n", error_ok(&err) ? "OK" : "Error");
    
    error_set(&err, ERR_NOT_FOUND, "File not found");
    printf("  After setting error: %s\n", error_ok(&err) ? "OK" : "Error");
    printf("  Error message: %s\n", err.message);
}

// =============================================================================
// Example 8: Version Header Pattern
// =============================================================================

// --- version.h ---
#ifndef VERSION_H
#define VERSION_H

#define LIB_VERSION_MAJOR 3
#define LIB_VERSION_MINOR 2
#define LIB_VERSION_PATCH 1

#define LIB_VERSION_STRING "3.2.1"

// Compute version as a single number for comparisons
#define LIB_VERSION_NUMBER \
    ((LIB_VERSION_MAJOR * 10000) + (LIB_VERSION_MINOR * 100) + LIB_VERSION_PATCH)

// Version checking macro
#define LIB_VERSION_AT_LEAST(major, minor, patch) \
    (LIB_VERSION_NUMBER >= ((major * 10000) + (minor * 100) + patch))

// Build information
#define LIB_BUILD_DATE __DATE__
#define LIB_BUILD_TIME __TIME__

// Feature availability based on version
#if LIB_VERSION_AT_LEAST(3, 0, 0)
    #define LIB_HAS_NEW_API 1
#else
    #define LIB_HAS_NEW_API 0
#endif

#if LIB_VERSION_AT_LEAST(3, 2, 0)
    #define LIB_HAS_ASYNC 1
#else
    #define LIB_HAS_ASYNC 0
#endif

typedef struct {
    int major;
    int minor;
    int patch;
    const char *string;
    const char *build_date;
    const char *build_time;
} LibVersion;

static inline LibVersion lib_get_version(void) {
    LibVersion v = {
        LIB_VERSION_MAJOR,
        LIB_VERSION_MINOR,
        LIB_VERSION_PATCH,
        LIB_VERSION_STRING,
        LIB_BUILD_DATE,
        LIB_BUILD_TIME
    };
    return v;
}

#endif /* VERSION_H */

void example_version_header(void) {
    printf("\n=== Example 8: Version Header Pattern ===\n");
    
    LibVersion ver = lib_get_version();
    
    printf("Library Version Information:\n");
    printf("  Version: %s\n", ver.string);
    printf("  Major: %d, Minor: %d, Patch: %d\n", 
           ver.major, ver.minor, ver.patch);
    printf("  Build: %s %s\n", ver.build_date, ver.build_time);
    printf("  Version number: %d\n", LIB_VERSION_NUMBER);
    printf("\n");
    
    printf("Feature availability:\n");
    printf("  New API (3.0.0+): %s\n", LIB_HAS_NEW_API ? "Yes" : "No");
    printf("  Async support (3.2.0+): %s\n", LIB_HAS_ASYNC ? "Yes" : "No");
    printf("\n");
    
    printf("Version checking:\n");
    printf("  >= 2.0.0: %s\n", LIB_VERSION_AT_LEAST(2, 0, 0) ? "Yes" : "No");
    printf("  >= 3.2.0: %s\n", LIB_VERSION_AT_LEAST(3, 2, 0) ? "Yes" : "No");
    printf("  >= 4.0.0: %s\n", LIB_VERSION_AT_LEAST(4, 0, 0) ? "Yes" : "No");
}

// =============================================================================
// Example 9: Module with Private Header
// =============================================================================

/*
 * Large modules often have a public header and a private/internal header.
 * The private header is only included by the module's implementation files.
 */

// --- BEGIN string_buffer.h (PUBLIC) ---
#ifndef STRING_BUFFER_H
#define STRING_BUFFER_H

#include <stddef.h>

// Opaque type
typedef struct StringBuffer StringBuffer;

// Public API
StringBuffer* strbuf_create(size_t initial_capacity);
void strbuf_destroy(StringBuffer *sb);
void strbuf_append(StringBuffer *sb, const char *str);
void strbuf_append_char(StringBuffer *sb, char c);
void strbuf_clear(StringBuffer *sb);
const char* strbuf_get(const StringBuffer *sb);
size_t strbuf_length(const StringBuffer *sb);

#endif /* STRING_BUFFER_H */
// --- END string_buffer.h ---

// --- BEGIN string_buffer_internal.h (PRIVATE) ---
#ifndef STRING_BUFFER_INTERNAL_H
#define STRING_BUFFER_INTERNAL_H

// Include public header
// #include "string_buffer.h"

// Private structure definition
struct StringBuffer {
    char *data;
    size_t length;
    size_t capacity;
};

// Private helper functions
static inline bool strbuf_grow(StringBuffer *sb, size_t needed) {
    if (sb->length + needed < sb->capacity) {
        return true;
    }
    
    size_t new_capacity = sb->capacity * 2;
    while (new_capacity < sb->length + needed) {
        new_capacity *= 2;
    }
    
    char *new_data = realloc(sb->data, new_capacity);
    if (new_data == NULL) {
        return false;
    }
    
    sb->data = new_data;
    sb->capacity = new_capacity;
    return true;
}

#endif /* STRING_BUFFER_INTERNAL_H */
// --- END string_buffer_internal.h ---

// Implementation (would be in string_buffer.c)
// #include "string_buffer_internal.h"

StringBuffer* strbuf_create(size_t initial_capacity) {
    StringBuffer *sb = malloc(sizeof(StringBuffer));
    if (sb == NULL) return NULL;
    
    size_t cap = (initial_capacity > 0) ? initial_capacity : 16;
    sb->data = malloc(cap);
    if (sb->data == NULL) {
        free(sb);
        return NULL;
    }
    
    sb->data[0] = '\0';
    sb->length = 0;
    sb->capacity = cap;
    
    return sb;
}

void strbuf_destroy(StringBuffer *sb) {
    if (sb) {
        free(sb->data);
        free(sb);
    }
}

void strbuf_append(StringBuffer *sb, const char *str) {
    if (sb == NULL || str == NULL) return;
    
    size_t len = strlen(str);
    if (!strbuf_grow(sb, len + 1)) return;
    
    strcpy(sb->data + sb->length, str);
    sb->length += len;
}

void strbuf_append_char(StringBuffer *sb, char c) {
    if (sb == NULL) return;
    
    if (!strbuf_grow(sb, 2)) return;
    
    sb->data[sb->length++] = c;
    sb->data[sb->length] = '\0';
}

void strbuf_clear(StringBuffer *sb) {
    if (sb) {
        sb->data[0] = '\0';
        sb->length = 0;
    }
}

const char* strbuf_get(const StringBuffer *sb) {
    return sb ? sb->data : "";
}

size_t strbuf_length(const StringBuffer *sb) {
    return sb ? sb->length : 0;
}

void example_private_header(void) {
    printf("\n=== Example 9: Module with Private Header ===\n");
    
    StringBuffer *sb = strbuf_create(0);
    
    strbuf_append(sb, "Hello");
    strbuf_append(sb, ", ");
    strbuf_append(sb, "World");
    strbuf_append_char(sb, '!');
    
    printf("String: \"%s\"\n", strbuf_get(sb));
    printf("Length: %zu\n", strbuf_length(sb));
    
    strbuf_clear(sb);
    strbuf_append(sb, "Cleared and new content");
    printf("After clear: \"%s\"\n", strbuf_get(sb));
    
    strbuf_destroy(sb);
    
    printf("\nNote: The internal structure and helper functions\n");
    printf("are hidden from users of the public API.\n");
}

// =============================================================================
// Main Function
// =============================================================================

int main(void) {
    printf("============================================================\n");
    printf("    HEADER FILES AND INCLUDE GUARDS IN C - EXAMPLES         \n");
    printf("============================================================\n");
    
    example_include_guards();
    example_multiple_inclusion();
    example_forward_declarations();
    example_opaque_pointers();
    example_inline_functions();
    example_cpp_compatibility();
    example_header_organization();
    example_version_header();
    example_private_header();
    
    printf("\n============================================================\n");
    printf("                  ALL EXAMPLES COMPLETED                     \n");
    printf("============================================================\n");
    
    return 0;
}
Examples - C Programming Tutorial | DeepML