C _Generic (C11)

Type-generic programming with compile-time selection

🎯 What is _Generic?

_Generic is a C11 feature that enables type-generic programming by selecting different expressions based on the type of an argument. It allows one macro to work with multiple data types, choosing the appropriate function at compile time.


#include <stdio.h>
#include <math.h>

// Type-generic macro for absolute value
#define ABS(x) _Generic((x), \
    int: abs, \
    long: labs, \
    float: fabsf, \
    double: fabs, \
    long double: fabsl \
)(x)

int main() {
    int i = -5;
    float f = -3.14f;
    double d = -2.718;
    
    printf("ABS(%d) = %d\n", i, ABS(i));
    printf("ABS(%.2f) = %.2f\n", f, ABS(f));
    printf("ABS(%.3f) = %.3f\n", d, ABS(d));
    
    return 0;
}
                                    

Output:

ABS(-5) = 5
ABS(-3.14) = 3.14
ABS(-2.718) = 2.718

Key _Generic Concepts

🔍

Type Selection

Chooses expression based on type

#define SQRT(x) _Generic((x), \
    float: sqrtf, \
    double: sqrt \
)(x)

Compile-time

Selection happens at compile time

// No runtime overhead
int x = 5;
int result = ABS(x);  // Calls abs(x)
🎨

Type Safety

Ensures correct function for each type

float f = 3.14f;
// Automatically calls sqrtf for float
float result = SQRT(f);
🔧

Default Case

Fallback for unmatched types

#define PRINT(x) _Generic((x), \
    int: printf("%d", x), \
    default: printf("unknown") \
)

🔹 Basic _Generic Syntax

_Generic enables type-generic programming by selecting code based on data types. The _Generic(expression, type1: code1, type2: code2, default: defaultCode) construct matches expression type and executes corresponding code. This powerful feature eliminates repetitive function overloading and creates truly generic algorithms. _Generic operates at compile-time, producing zero runtime overhead while maintaining type safety and code flexibility for mathematical and utility functions.

#include <stdio.h>

// Basic _Generic syntax demonstration
#define TYPE_NAME(x) _Generic((x), \
    int: "integer", \
    float: "float", \
    double: "double", \
    char: "character", \
    char*: "string", \
    default: "unknown type" \
)

#define MAX(a, b) _Generic((a), \
    int: ((a) > (b) ? (a) : (b)), \
    float: ((a) > (b) ? (a) : (b)), \
    double: ((a) > (b) ? (a) : (b)) \
)

int main() {
    int i = 42;
    float f = 3.14f;
    double d = 2.718;
    char c = 'A';
    char* s = "Hello";
    
    printf("Type of %d: %s\n", i, TYPE_NAME(i));
    printf("Type of %.2f: %s\n", f, TYPE_NAME(f));
    printf("Type of %.3f: %s\n", d, TYPE_NAME(d));
    printf("Type of '%c': %s\n", c, TYPE_NAME(c));
    printf("Type of \"%s\": %s\n", s, TYPE_NAME(s));
    
    printf("MAX(10, 20) = %d\n", MAX(10, 20));
    printf("MAX(3.5f, 2.1f) = %.1f\n", MAX(3.5f, 2.1f));
    
    return 0;
}

Output:

Type of 42: integer
Type of 3.14: float
Type of 2.718: double
Type of 'A': character
Type of "Hello": string
MAX(10, 20) = 20
MAX(3.5, 2.1) = 3.5

🔹 Practical Applications

_Generic solves real-world problems through type-generic MAX functions and mathematical operations. Create single MAX() macro working with integers, floats, and doubles without multiple implementations. Implement generic print functions displaying any numeric type appropriately. Build type-safe MIN functions eliminating duplicate code. These applications demonstrate _Generic power for writing clean, maintainable code handling multiple types elegantly and efficiently.

🔸 Mathematical Functions

#include <stdio.h>
#include <math.h>

// Type-generic mathematical operations
#define SIN(x) _Generic((x), \
    float: sinf, \
    double: sin, \
    long double: sinl \
)(x)

#define POW(x, y) _Generic((x), \
    float: powf, \
    double: pow, \
    long double: powl \
)(x, y)

#define ROUND(x) _Generic((x), \
    float: roundf, \
    double: round, \
    long double: roundl \
)(x)

int main() {
    float angle_f = 3.14159f / 4;  // 45 degrees in radians
    double angle_d = 3.14159 / 6;  // 30 degrees in radians
    
    printf("sin(45°) = %.3f\n", SIN(angle_f));
    printf("sin(30°) = %.3f\n", SIN(angle_d));
    
    printf("2^3 = %.0f\n", POW(2.0, 3.0));
    printf("3.7 rounded = %.0f\n", ROUND(3.7));
    
    return 0;
}

🔸 Generic Printing Function

#include <stdio.h>

// Type-generic print function
#define PRINT(x) _Generic((x), \
    int: printf("Integer: %d\n", x), \
    float: printf("Float: %.2f\n", x), \
    double: printf("Double: %.3f\n", x), \
    char: printf("Character: '%c'\n", x), \
    char*: printf("String: \"%s\"\n", x), \
    default: printf("Unknown type\n") \
)

// Generic comparison
#define EQUAL(a, b) _Generic((a), \
    int: ((a) == (b)), \
    float: (fabsf((a) - (b)) < 0.001f), \
    double: (fabs((a) - (b)) < 0.000001), \
    char*: (strcmp((a), (b)) == 0) \
)

int main() {
    int num = 42;
    float pi = 3.14f;
    double e = 2.718281828;
    char letter = 'X';
    char* message = "Hello, World!";
    
    PRINT(num);
    PRINT(pi);
    PRINT(e);
    PRINT(letter);
    PRINT(message);
    
    printf("5 == 5: %s\n", EQUAL(5, 5) ? "true" : "false");
    printf("3.14f == 3.14f: %s\n", EQUAL(3.14f, 3.14f) ? "true" : "false");
    
    return 0;
}

🔹 Advanced Usage Tips

Master advanced _Generic techniques for sophisticated type-generic programming patterns. Combine _Generic with variadic macros for flexible, powerful abstractions. Nest _Generic expressions to handle complex type hierarchies and relationships. Use _Generic with typeof extensions for enhanced type detection capabilities. These advanced patterns enable library authors to create intuitive, powerful APIs hiding implementation complexity. Understanding advanced usage elevates programming sophistication.

✅ Best Practices:

  • Use with math.h: Perfect for type-generic math functions
  • Include default case: Handle unexpected types gracefully
  • Combine with macros: Create powerful generic interfaces
  • Document types: Clearly specify supported types

⚠️ Limitations:

  • C11 required: Not available in older C standards
  • Compile-time only: Cannot select based on runtime values
  • Type exact match: No automatic type promotion
  • Complex syntax: Can become hard to read
// Advanced: Nested _Generic for multi-parameter functions
#define SWAP(a, b) do { \
    typeof(a) temp = a; \
    a = b; \
    b = temp; \
} while(0)

// Using _Generic with function pointers
typedef void (*print_func_t)(void*);

#define GET_PRINTER(x) _Generic((x), \
    int*: print_int, \
    float*: print_float, \
    char**: print_string \
)

🧠 Test Your Knowledge

When does _Generic perform type selection?