把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;
}
posted @ 2025-06-13 10:08  沙老师  阅读(2)  评论(0)    收藏  举报