把malloc/calloc/realloc/free合并成一个安全的宏,以及测试代码
标准化了指针分配前检查NULL、释放后置NULL、新分配的内存初始化为0的动作。唯一的缺陷是,指针声明时候必须初始化为NULL,这个无法用宏优雅地写出来。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define log_error(__arg_format, ...) \
printf("ERROR %s:%d:%s: " __arg_format "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__)
#define fatal(__arg_format, ...) \
do { \
log_error("Fatal error: " __arg_format, ##__VA_ARGS__); \
abort(); \
} while (0)
#define enforce(__arg_condition) \
do { \
if (!(__arg_condition)) { \
fatal("Enforcement failed: %s", #__arg_condition); \
} \
} while (0)
#if defined(_WIN32)
#include <malloc.h>
#define allocated_size _msize
#elif defined(__linux__)
#include <malloc.h>
#define allocated_size malloc_usable_size
#elif defined(__APPLE__)
#include <malloc/malloc.h>
#define allocated_size malloc_size
#else
#error Looking up allocated memory block size is not supported in this platform.
#endif
#define allocate(__arg_pointer, __arg_unit_count) \
do { \
typeof(__arg_unit_count) __unit_count = __arg_unit_count; \
size_t __size_per_unit = sizeof(typeof(*__arg_pointer)); \
size_t __size = __unit_count * __size_per_unit; \
if (__arg_pointer == NULL) { \
if (__unit_count > 0) { \
__arg_pointer = (typeof(__arg_pointer))calloc(__unit_count, __size_per_unit); \
enforce(__arg_pointer != NULL); \
} \
} else { \
if (__unit_count > 0) { \
size_t __old_size = allocated_size(__arg_pointer); \
__arg_pointer = (typeof(__arg_pointer))realloc(__arg_pointer, __size); \
enforce(__arg_pointer != NULL); \
if (__size > __old_size) { \
memset((char *)(__arg_pointer) + __old_size, 0, __size - __old_size); \
} \
} else { \
free(__arg_pointer); \
__arg_pointer = NULL; \
} \
} \
} while (0)
struct foo {
char a;
short b;
long c;
long long d;
};
// msvc编译选项:cl /W3 /utf-8 /std:clatest
// 打开任务管理器查看内存是否泄露
int main() {
struct foo *foo = NULL;
struct foo *ptr;
int old_count = 0;
int new_count = 0;
int offset;
srand((unsigned)time(NULL));
for (;;) {
// 检查旧空间是否为0xff
for (offset = 0; offset < old_count; offset++) {
ptr = foo + offset;
enforce(ptr->a == -1);
enforce(ptr->b == -1);
enforce(ptr->c == -1);
enforce(ptr->d == -1);
}
// 设置一个较小值让更多0出现以测试free()
new_count = rand() % 10;
allocate(foo, new_count);
// 检查新空间是否为0
for (offset = old_count; offset < (new_count - old_count); offset++) {
ptr = foo + offset;
enforce(ptr->a == 0);
enforce(ptr->b == 0);
enforce(ptr->c == 0);
enforce(ptr->d == 0);
}
// 填入0xff
for (offset = 0; offset < new_count; offset++) {
ptr = foo + offset;
ptr->a = -1;
ptr->b = -1;
ptr->c = -1;
ptr->d = -1;
}
old_count = new_count;
}
return EXIT_SUCCESS;
}

浙公网安备 33010602011771号