代码之家  ›  专栏  ›  技术社区  ›  meguli

如何在C中为通用内存池在指针之间自由转换?

  •  1
  • meguli  · 技术社区  · 7 年前

    我开始实现一个通用内存池。这是为了学习,所以,肯定有很多错误。但是,我在向前走。现在我被一个新的部分绊倒了。首先,代码

    #include <stdlib.h>
    #include <string.h>
    #include <stddef.h>
    #include <stdint.h>
    #include <stdio.h>
    
    typedef enum { FALSE, TRUE } BOOL;
    
    typedef struct mem_block {
        uint8_t* data;
        size_t block_size;
        size_t pool_position;
        BOOL is_freed;
    } mem_block;
    
    typedef struct mem_pool {
        mem_block* blocks;
        size_t index;
        size_t pool_size;
    } mem_pool;
    
    mem_pool *pool_init() {
        mem_pool *pool = (mem_pool *) malloc(sizeof(mem_pool));
        pool->pool_size = (size_t) 128;
        mem_block* blk = (mem_block *) malloc(pool->pool_size * sizeof (mem_block));
        pool->index = 0;
        pool->blocks = blk;
    
        return pool;
    }
    
    void *pool_allocate(mem_pool **pool, size_t size) {
        mem_pool* _pool = *pool;
        size_t free_portion = _pool->pool_size - _pool->index;
    
        if(size < free_portion){
            mem_block* allocated_blk = _pool->blocks + _pool->index;
            uint8_t* data = (uint8_t*) malloc(size * sizeof(uint8_t));
            allocated_blk->data = data;
            allocated_blk->block_size = size;
            allocated_blk->is_freed = FALSE;
            allocated_blk->pool_position = _pool->index;
            _pool->index += size; 
            return (void *) allocated_blk->data;
        }
        else{
            printf("Pool is out of memory");
            return NULL;
        }
    }
    
    /*void pool_free(mem_pool **pool, void *block) {
        mem_block* cur = (mem_block*) block;
        mem_block* next = cur + 1;
        // override the unneeded memory
    memmove(cur, next, (*pool)->pool_size - next->pool_position);
    }*/
    
    typedef struct complex {
        double i;
        double r;
    } complex;
    
    mem_pool *GLOBAL_POOL = pool_init();
    int main() {
        complex *c1 = (complex *) pool_allocate(&GLOBAL_POOL, sizeof(complex));
        c1->r = 1.0;
        c1->i = 2.0;
        printf("Value is (%f + %fi)\n", c1->r, c1->i);
        printf("Remaining free size is %ld\n", GLOBAL_POOL->pool_size -   GLOBAL_POOL->index);
    
        complex *c2 = (complex *) pool_allocate(&GLOBAL_POOL, sizeof(complex));
        c2->r = 2.0;
        c2->i = 3.0;
        printf("Value is (%f + %fi)\n", c2->r, c2->i);
        printf("Remaining free size is %ld\n", GLOBAL_POOL->pool_size - GLOBAL_POOL->index);
    
        mem_block* cur = (mem_block *) &c2;
        printf("Position of c2 is %ld\n", cur->pool_position);
        printf("Adress of c2's block is %x\n", cur);
        printf("Address of c2 is %x\n", &c2);
        printf("c2 points to %x\n", c2);
    
        complex *c3 = (complex *) pool_allocate(&GLOBAL_POOL, sizeof(complex));
        c3->r = 3.0;
        c3->i = 4.0;
        printf("Value is (%f + %fi)\n", c3->r, c3->i);
        printf("Remaining free size is %ld\n", GLOBAL_POOL->pool_size - GLOBAL_POOL->index);
    
        cur = (mem_block *) &c3;
        printf("Position of c3 is %ld\n", cur->pool_position);
        printf("Adress of c3's block is %x\n", cur);
        printf("Address of c3 is %x\n", &c3);
        printf("c3 points to %x\n", c3);
    
        complex *c4 = (complex *) pool_allocate(&GLOBAL_POOL, sizeof(complex));
        c4->r = 4.0;
        c4->i = 5.0;
        printf("Value is (%f + %fi)\n", c4->r, c4->i);
        printf("Remaining free size is %ld\n", GLOBAL_POOL->pool_size - GLOBAL_POOL->index);
    
        complex *c5 = (complex *) pool_allocate(&GLOBAL_POOL, sizeof(complex));
        c5->r = 5.0;
        c5->i = 6.0;
        printf("Value is (%f + %fi)\n", c5->r, c5->i);
        printf("Remaining free size is %ld\n", GLOBAL_POOL->pool_size - GLOBAL_POOL->index);
    
        complex *c6 = (complex *) pool_allocate(&GLOBAL_POOL, sizeof(complex));
        c6->r = 6.0;
        c6->i = 7.0;
        printf("Value is (%f + %fi)\n", c6->r, c6->i);
        printf("Remaining free size is %ld\n", GLOBAL_POOL->pool_size - GLOBAL_POOL->index);
    
        complex *c7 = (complex *) pool_allocate(&GLOBAL_POOL, sizeof(complex));
        c7->r = 7.0;
        c7->i = 8.0;
        printf("Value is (%f + %fi)\n", c7->r, c7->i);
        printf("Remaining free size is %ld\n", GLOBAL_POOL->pool_size - GLOBAL_POOL->index);
    
        complex *c8 = (complex *) pool_allocate(&GLOBAL_POOL, sizeof(complex));
        if(c8 != NULL) {
            c8->r = 3.0;
            c8->i = 4.0;
            printf("Value is (%f + %fi)\n", c8->r, c8->i);
        }else {
            return -1;   
        }
        return 0;
    }
    

    目前,它的大小是128字节,但一旦我得到了基本的,我会使它的大小无限。分配可能工作正常,您可以看到输出,并看到我可以设置分配的指针和使用值。除此之外,我还想实现 free pool_free . 执行 memmove ,我需要知道 mem_block 我正在删除。

    pool_allocate ,您可以看到我返回 data malloc 内存块 数据 .

    mem_block* cur = (mem_block *) &c3;
    printf("Position of c3 is %ld\n", cur->pool_position);
    printf("Adress of c3's block is %x\n", cur);
    printf("Address of c3 is %x\n", &c3);
    printf("c3 points to %x\n", c3);
    

    c3 这里是用 池分配 以及指向数据的指针, uint8_t* complex * 待使用。所以呢 c3级 指向 complex 对象。解引用应该给出实际的数据,我认为这是可行的。但它也有自己的地址。我想这个地址和 数据 其块的指针,因为它是 . 所以我把它随便丢给了一个 mem_block*

    printf("Position of c3 is %ld\n", cur->pool_position);
    

    Position of c3 is 0 或者其他胡言乱语。我希望看到像16,32等东西,因为每一个 是16字节。那么,为什么你认为演员们

    mem_block* cur = (mem_block *) &c3;
    

    不让我和你一起工作 好像是一个 内存块 ? 也许我没有通过引用正确地传递指针,所以指向的东西的更改在外面看不到?这似乎不太可能,因为我可以按预期处理分配的对象,但谁知道呢?我检查了每一部分,但仍然不能解决问题。

    1 回复  |  直到 7 年前
        1
  •  1
  •   Goswin von Brederlow    7 年前

    在malloc中的工作方式是,每个块都有一个头(管理结构),在alloc中,您将在该结构之后返回地址。然后在空闲的时候,你知道你的地址在报头之后,所以你可以从中计算出实际报头的地址。

    void alloc(size_t size) {
        ...
        struct mem_block *block = <address of block you return>
        return &block[1];
    }
    
    void free(void *addr) {
        struct mem_block *block = addr;
        block[-1].is_freed = false;
        ...
    }