这个内存分配器如何工作?

时间:2016-10-31 18:35:56

标签: c

所以,我只是坐下来决定写一个内存分配器。我累了,所以我只是扔了一些东西。我最终得到的是:

#include <stdio.h>
#include <stdlib.h>

#define BUFSIZE 1024

char buffer[BUFSIZE];
char *next = buffer;

void *alloc(int n){
    if(next + n <= buffer + BUFSIZE){
        next += n;
        return (void *)(next - n);
    }else{
        return NULL;
    }
}

void afree(void *c){
    next = (char *)c;
}

int main(){
    int *num = alloc(sizeof(int));
    *num = 5643;
    printf("%d: %d", *num, sizeof(int));
    afree(num);
}

由于某种原因,这是有效的。但我无法解释为什么它有效。这可能与我累了这个事实有关,但我真的不明白它为什么会起作用。所以,这就是它应该做的,逻辑上,并且据我所知:

  1. 它创建一个char数组,其指针指向数组的第一个元素。

  2. 当我调用alloc值为4(这是int的大小,正如我在下面测试过的那样)时,它应该设置为指向数组的第四个元素。然后它应该返回一个char指针,指向转换为void指针的数组的前4个字节。

  3. 然后我将该值设置为大于char的最大值。 C应该意识到这是不可能的,然后应该将其截断为* num%sizeof(char)。

  4. 我猜测为什么会这样:当char指针被转换为void指针然后变成一个整数时,它会以某种方式改变指针的大小,使它能够指向一个整数。 (我不仅尝试了这个带整数的内存分配器,而且还使用了结构,它似乎也适用于它们。)

    这个猜测是正确的,还是我太累了想不到?

    编辑: This is what it looks like in my mind

    编辑2:我想我已经明白了。我意识到我昨天的措词非常糟糕。抛弃我的事实是返回的指针实际指向一个char,但我仍然能以某种方式存储一个整数值。

3 个答案:

答案 0 :(得分:1)

发布的allocator实现了标记和发布分配方案:

    如果竞技场中至少有alloc(size)个未分配的字节,则
  • size返回有效指针。可用尺寸相应减小。请注意,此指针只能用于存储字节,因为它没有正确对齐其他任何内容。此外,根据对C标准的严格解释,即使指针正确对齐,使用它作为指向任何其他类型的指针也会违反严格的别名规则。

  • afree(ptr)将竞技场重置为alloc()返回ptr之前的状态。使afree(NULL)将竞技场重置为初始状态将是一个有用的扩展。

请注意,main()函数尝试使用alloc(sizeof(int))返回的指针作为指向int的指针。这会调用未定义的行为,因为无法保证buffer已正确对齐此行,并且因为违反了严格的别名规则。

另请注意,第二个参数的printf格式printf("%d: %d", *num, sizeof(int));不正确。如果C运行时库太旧而无法支持printf("%d: %zd", *num, sizeof(int));,则应为printf("%d: %d", *num, (int)sizeof(int));%zd

答案 1 :(得分:0)

其实!我想出了这个行为的原因!这就是我想知道的,然而,昨天我不太善于说出自己的话语(对不起)。我修改了我的代码:

#include <stdio.h>
#include <stdlib.h>

#define BUFSIZE 1024

char buffer[BUFSIZE];
char *next = buffer;

void *alloc(int n){
    if(next + n <= buffer + BUFSIZE){
        next += n;
        return (void *)(next - n);
    }else{
        return NULL;
    }
}

void afree(void *c){
    next = (char *)c;
}

int main(){
    int *num = alloc(sizeof(int));
    *num = 346455;
    printf("%d: %d\n", *num, (int)sizeof(int));
    printf("%d, %d, %d, %d", *(next - 4), *(next - 3), *(next - 2), *(next - 1));
    afree(num);
}

现在,最后一个printf产生“87,73,5,0”。 如果将所有值转换为大二进制值,则得到:00000000 00000101 01001001 01010111.如果取二进制值并将其转换为十进制,则得到* num的原始值,即346455.因此,基本上它将整数为4个字节并将它们放入数组的不同元素中。我认为这是实现定义的,与little endian和big endian有关。它是否正确?我的第一个预测是它会截断整数并基本上将值设置为(整数值)%sizeof(char)。

答案 2 :(得分:-1)

int *num = alloc(sizeof(int));

说 - '这是一个指向某个空间的指针(alloc),让我们说它指向一个整数(int *)。'

你说

 *num = 5643;

其中说 - 将该整数设置为5643。

为什么它不起作用 - 假设alloc实际上返回一个指向一个可以容纳整数的良好内存块的指针