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 \
)