C语言中带未知类型参数的泛型函数实现及扩展应用咨询
for_each Function More Versatile Great question—this is a classic hurdle when writing generic code in C, since the language lacks built-in parametric polymorphism like higher-level languages. Let's walk through practical ways to make your for_each function work seamlessly with more functions (like math operations) without writing tedious wrapper functions manually.
1. Auto-Generate Wrappers with Macros
The most straightforward fix for reducing boilerplate is to use a macro that dynamically creates the wrapper function you need based on the target function's argument type. This eliminates manual repetition while keeping your original for_each function intact.
Here's the macro:
#define GENERATE_WRAPPER(wrapper_name, target_func, arg_type) \ void wrapper_name(void *arg) { \ target_func(*(arg_type*)arg); \ }
Example Usage
For close(int fd):
// Auto-generate the close wrapper—no manual code needed! GENERATE_WRAPPER(close_fd, close, int) // For a math function like sqrt(double) GENERATE_WRAPPER(sqrt_wrapper, sqrt, double) int main() { // Example array of file descriptors (storing pointers to ints) int fds[] = {1, 2, 3}; void* fd_array[] = {(void*)&fds[0], (void*)&fds[1], (void*)&fds[2], NULL}; for_each(fd_array, close_fd); // Example array of doubles for sqrt double nums[] = {4.0, 9.0, 16.0}; void* num_array[] = {(void*)&nums[0], (void*)&nums[1], (void*)&nums[2], NULL}; for_each(num_array, sqrt_wrapper); return 0; }
2. Use C11 _Generic for Compile-Time Type Matching
If you're working with C11 or later, _Generic lets you create type-aware macros that eliminate wrapper functions entirely. This approach is cleaner at the call site and keeps type safety checks at compile time.
Generic for_each Macro
Replace your standalone for_each function with a macro that handles type conversion directly:
#define FOR_EACH_GENERIC(array, func, elem_type) \ for (size_t i = 0; array[i] != NULL; ++i) { \ func(*(elem_type*)array[i]); \ }
Example Usage
Now you can call it directly without any wrappers:
int main() { int fds[] = {1, 2, 3}; void* fd_array[] = {(void*)&fds[0], (void*)&fds[1], (void*)&fds[2], NULL}; // Directly pass the function and type FOR_EACH_GENERIC(fd_array, close, int); double nums[] = {4.0, 9.0, 16.0}; void* num_array[] = {(void*)&nums[0], (void*)&nums[1], (void*)&nums[2], NULL}; FOR_EACH_GENERIC(num_array, sqrt, double); return 0; }
3. Extend for_each with User Data (For Advanced Flexibility)
If you need even more control (e.g., passing additional parameters to the target function), modify your for_each to accept a void* user_data parameter. This lets you pass context or type info to your wrapper functions.
Updated for_each Function
void for_each(void *array[], void (*func)(void *, void *), void *user_data) { for (size_t i = 0; array[i] != NULL; ++i) { func(array[i], user_data); } }
Generic Wrapper Macro for This Version
#define GENERATE_CONTEXT_WRAPPER(wrapper_name, target_func, arg_type) \ void wrapper_name(void *arg, void *user_data) { \ // Use user_data if you need extra parameters—here we ignore it for simplicity (void)user_data; \ target_func(*(arg_type*)arg); \ }
Example Usage
GENERATE_CONTEXT_WRAPPER(close_fd_ctx, close, int) int main() { int fds[] = {1, 2, 3}; void* fd_array[] = {(void*)&fds[0], (void*)&fds[1], (void*)&fds[2], NULL}; for_each(fd_array, close_fd_ctx, NULL); return 0; }
Key Notes to Avoid Bugs
- Type Safety: Always ensure your
void*array stores pointers to the correct type—never cast non-pointer values (like rawintfds) directly tovoid*(this is non-portable and risky). - Termination Condition: Your
array[i] != NULLcheck relies on the array ending with aNULLpointer—make sure this is consistent across all uses. - Function Signatures: The target function must accept a single argument of the type you specify (adjust the macros if you need functions with multiple arguments).
内容的提问来源于stack exchange,提问作者B14s

