首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言統一內存管理入口:封裝 malloc/free 實現 new 風格分配與自動錯誤處理

     編輯:關於C語言

動機:簡化 malloc 錯誤檢查樣板代碼

標準模式繁瑣:

struct person *p = malloc(sizeof(struct person));
if (!p) { fprintf(stderr, "malloc failed"); /* 處理錯誤 */ }
... free(p);

參考高級語言 new:分配失敗直接終止程序(內存耗盡時繼續運行意義不大)。構建統一入口宏,自動檢查、初始化、記錄調用位置。

接口設計

// scalloc.h
#ifndef _H_SIMPLEC_SCALLOC
#define _H_SIMPLEC_SCALLOC
#include <stdlib.h>

// 內部函數(帶文件/行/函數信息)
void sm_free_(void *ptr, const char *file, int line, const char *func);
void *sm_malloc_(size_t sz, const char *file, int line, const char *func);
void *sm_realloc_(void *ptr, size_t sz, const char *file, int line, const char *func);

// 公開宏(自動填充 __FILE__ __LINE__ __func__)
#define sm_free(ptr)      sm_free_(ptr, __FILE__, __LINE__, __func__)
#define sm_malloc(sz)     sm_malloc_(sz, __FILE__, __LINE__, __func__)
#define sm_calloc(n, sz)  sm_malloc_((n)*(sz), __FILE__, __LINE__, __func__)
#define sm_realloc(p, sz) sm_realloc_(p, sz, __FILE__, __LINE__, __func__)

// 可選:全局替換標準函數名
#ifndef _SIMPLEC_SCALLOC_CLOSE
#define free   sm_free
#define malloc sm_malloc
#define calloc sm_calloc
#define realloc sm_realloc
#endif
#endif

實現細節

glibc calloc 源碼片段

元數據頭部

typedef enum { HF_Alloc, HF_Free } header_e;
struct header {
    header_e flag;       // 狀態標記
    int line;            // 分配行號
    const char *file;    // 文件名
    const char *func;    // 函數名
};

每次分配在用戶內存前插入 struct header(16-24 字節開銷),用於雙重釋放檢測、洩漏定位。

核心函數

void *sm_malloc_(size_t sz, const char *file, int line, const char *func) {
    struct header *h = malloc(sz + sizeof(struct header));
    if (!h) {
        fprintf(stderr, "%s:%d:%s alloc fail\n", file, line, func);
        exit(EXIT_FAILURE);
    }
    h->flag = HF_Alloc; h->line = line; h->file = file; h->func = func;
    memset(h + 1, 0, sz);  // 返回用戶區並清零
    return h + 1;
}

static struct header *_header_get(void *ptr, const char *file, int line, const char *func) {
    struct header *h = (struct header *)ptr - 1;
    if (h->flag != HF_Alloc) {
        fprintf(stderr, "%s:%d:%s double/invalid free flag=%d\n", file, line, func, h->flag);
        exit(EXIT_FAILURE);
    }
    return h;
}

void *sm_realloc_(void *ptr, size_t sz, const char *file, int line, const char *func) {
    if (!ptr) return sm_malloc_(sz, file, line, func);
    struct header *h = _header_get(ptr, file, line, func);
    h->flag = HF_Free;
    struct header *nh = realloc(h, sz + sizeof(struct header));
    nh->flag = HF_Alloc; nh->line = line; nh->file = file; nh->func = func;
    return nh + 1;
}

void sm_free_(void *ptr, const char *file, int line, const char *func) {
    if (ptr) {
        struct header *h = _header_get(ptr, file, line, func);
        h->flag = HF_Free;
        free(h);
    }
}

測試驗證

// main.c
#include "scalloc.h"
int main() {
    int *p = malloc(10); free(p);
    puts("start test...");
    free(p);  // 故意雙重釋放觸發檢測
    getchar(); return 0;
}

雙重釋放檢測輸出

輸出顯示精確定位到文件、行號、函數,且識別出 flag 異常。

開銷分析

  • 64 位系統:每次分配額外 24 字節(flag(4)+line(4)+file(8)+func(8),對齊後)。
  • 100 萬次分配約 23 MB 開銷,可接受。
  • 一次額外指針運算與分支檢查,性能影響微乎其微。

總結

核心思想:偷梁換柱——在用戶內存前植入元數據,統一入口宏自動捕獲上下文,失敗即退出,釋放時驗證完整性。可直接集成到項目構建系統中替換標準分配器。

插圖

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved