如何判断指针指向文件或缓冲区?合并C可变参数释放函数需求
解决方案
C语言没有运行时类型信息(RTTI),无法自动判断一个指针指向的是FILE对象还是普通缓冲区,所以要合并两个函数,必须从调用端显式传递类型标识或处理逻辑,以下是两种实用方案:
方案一:使用枚举标记类型
先定义类型枚举,让函数明确每个参数的处理方式:
#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> typedef enum { CLEANUP_FILE, CLEANUP_BUFFER } CleanupType; int cleanup(int n, ...) { va_list ptr; va_start(ptr, n); int count = 0; for (int i = 0; i < n; i++) { CleanupType type = va_arg(ptr, CleanupType); void** pp = va_arg(ptr, void**); if (*pp == NULL) continue; switch (type) { case CLEANUP_FILE: fclose(*(FILE**)pp); break; case CLEANUP_BUFFER: free(*pp); break; default: continue; // 忽略未知类型 } *pp = NULL; count++; } va_end(ptr); return count; }
调用示例
// 同时关闭1个文件、释放2个缓冲区 cleanup(3, CLEANUP_FILE, &fp1, CLEANUP_BUFFER, &bp1, CLEANUP_BUFFER, &bp2);
方案二:使用回调函数(更灵活)
把清理逻辑抽象成回调函数,让合并后的函数只负责通用流程,具体操作交给回调实现:
#include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> typedef void (*CleanupFunc)(void*); int cleanup(int n, ...) { va_list ptr; va_start(ptr, n); int count = 0; for (int i = 0; i < n; i++) { CleanupFunc func = va_arg(ptr, CleanupFunc); void** pp = va_arg(ptr, void**); if (*pp == NULL || func == NULL) continue; func(*pp); *pp = NULL; count++; } va_end(ptr); return count; } // 文件清理回调 void cleanup_file(void* p) { fclose((FILE*)p); } // 缓冲区清理回调 void cleanup_buffer(void* p) { free(p); }
调用示例
// 关闭2个文件、释放1个缓冲区 cleanup(3, cleanup_file, &fp1, cleanup_file, &fp2, cleanup_buffer, &bp1);
注意事项
- 两种方案都依赖调用端传递正确的类型标记或回调,否则会触发未定义行为;
void**的类型转换是安全的,同一平台下所有指针的内存占用大小一致;- 函数返回值依然统计成功清理的对象数量,和原函数逻辑保持一致。
内容的提问来源于stack exchange,提问作者csharp
相关产品推荐
相关产品推荐

