C中的内存分配

发布于 2024-08-09 08:14:46 字数 614 浏览 6 评论 0原文

下面是 ma​​lloc() 的一个非常非常简单的版本,似乎为我分配了一些空间,但除了没有 free() 之外,我不检查我是否已经超出了分配的空间,如何检查代码是否正确?

“C”专家会因为任何明显的错误而扇我耳光吗?

#include <stdio.h>
#include <unistd.h>

#define MAX_MEMORY 1024 * 1024 * 2 /* 2MB of memory */

void *stack = NULL; /* pointer to available stack */
void * memoryAlloc(size) {
    if (stack == NULL)
        stack = sbrk(MAX_MEMORY); /* give us system memory */

    void *pointer;
    pointer = (void *)stack + size; /* we always have space :) */
    stack += size; /* move in stack forward as space allocated */
    return pointer;
}

the following is a very very simple version of malloc() and seems to allocate some space to me, but apart from the fact that there is no free() and I don't check if I've overrun the allocated space, how can I check that the code is correct?

Any obvious blunders that "C" experts would slap me for?

#include <stdio.h>
#include <unistd.h>

#define MAX_MEMORY 1024 * 1024 * 2 /* 2MB of memory */

void *stack = NULL; /* pointer to available stack */
void * memoryAlloc(size) {
    if (stack == NULL)
        stack = sbrk(MAX_MEMORY); /* give us system memory */

    void *pointer;
    pointer = (void *)stack + size; /* we always have space :) */
    stack += size; /* move in stack forward as space allocated */
    return pointer;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

哆兒滾 2024-08-16 08:14:46

除了 Ned Batchelder 指出的基本问题之外,一个更微妙的问题是分配器必须返回一个与正在分配的任何对象正确对齐的地址。在某些平台(x86)上,除了性能问题外,这可能并不重要,但在许多平台上,这完全是一个问题。

我还必须执行 (char*) 强制转换来执行 stack 指针算术(您不能对 void* 类型进行指针算术) )。

并且您应该在 MAX_MEMORY 宏中的表达式两边加上括号。我认为如果没有它们,您不会遇到任何优先级问题,因为所有比乘法优先级高的运算符无论如何都不是正确的语法。对于宏,总是安全总比后悔好。 (至少有一个例外,[] 运算符只能绑定到 2 而不是整个 MAX_MEMORY 表达式,但这将是一个看到 MAX_MEMORY[arrayname] 的情况非常奇怪,即使它在语法上是有效的)。

事实上,我会把它变成一个枚举。

您可以通过返回与系统上的任何基本数据类型正确对齐的内存块(可能是 8 字节对齐)来保持分配器简单:

/* Note: the following is untested                   */
/*       it includes changes suggested by Batchelder */

#include <stdio.h>
#include <unistd.h>

enum {
    kMaxMemory = 1024 * 1024 * 2, /* 2MB of memory */
    kAlignment = 8
};

void *stack = NULL; /* pointer to available stack */
void * memoryAlloc( size_t size) {
    void *pointer;

    size = (size + kAlignment - 1) & ~(kAlignment - 1);   /* round size up so allocations stay aligned */

    if (stack == NULL)
    stack = sbrk(kMaxMemory); /* give us system memory */

    pointer = stack; /* we always have space :) */
    stack = (char*) stack + size;   /* move in stack forward as space allocated */
    return pointer;
}

In addition to the basic problems Ned Batchelder pointed out, a much more subtle problem is that an allocator has to return an address that's properly aligned for whatever object is being allocated. On some platforms (x86) this may not matter except for performance issues, but on many platforms it's a complete deal breaker.

I also had to perform a (char*) cast to perform the stack pointer arithmetic (you can't do pointer arithmetic on void* types).

And you should put parens around the expression in the MAX_MEMORY macro. I don't think there are any precedence problems you'd get into without them, as all the high precedence operators than multiplication wouldn't be correct syntax anyway. With macros, it's always better safe than sorry. (There's at least one exception where the [] operator could bind only to the 2 and not the whole MAX_MEMORY expression, but it would be a very weird situation to see MAX_MEMORY[arrayname], even if it's syntactically valid).

As a matter of fact, I would have made it an enum.

You can probably keep the allocator simple by returning a block of memory that's properly aligned for any basic data type on the system (maybe an 8 byte alignment):

/* Note: the following is untested                   */
/*       it includes changes suggested by Batchelder */

#include <stdio.h>
#include <unistd.h>

enum {
    kMaxMemory = 1024 * 1024 * 2, /* 2MB of memory */
    kAlignment = 8
};

void *stack = NULL; /* pointer to available stack */
void * memoryAlloc( size_t size) {
    void *pointer;

    size = (size + kAlignment - 1) & ~(kAlignment - 1);   /* round size up so allocations stay aligned */

    if (stack == NULL)
    stack = sbrk(kMaxMemory); /* give us system memory */

    pointer = stack; /* we always have space :) */
    stack = (char*) stack + size;   /* move in stack forward as space allocated */
    return pointer;
}
筱武穆 2024-08-16 08:14:46

有一些问题:

  1. 您在函数中间声明 pointer,这在 C 中是不允许的。

  2. 您将指针设置为 stack+size,但您希望它只是 stack。否则,您将返回一个指向您正在分配的内存块末尾的指针。因此,如果您的调用者使用该指针处的所有 size 字节,他将与另一个内存块重叠。如果您在不同时间获得不同大小的块,则会有两个调用者尝试使用相同字节的内存。

  3. 当您执行stack += size时,您不是按size字节而是按sizestack > void*'s,它几乎总是更大。

There are a few problems:

  1. You declare pointer in the middle of the function, which isn't allowed in C.

  2. You set pointer to stack+size, but you want it to be just stack. Otherwise, you're returning a pointer to the end of the block of memory you're allocating. As a result, if your caller uses all size bytes at that pointer, he'll be overlapping with another block of memory. If you get different sized blocks at different times, you'll have two callers trying to use the same bytes of memory.

  3. When you do stack += size, you're incrementing stack not by size bytes but by size void*'s, which is almost always larger.

无畏 2024-08-16 08:14:46

首先,正如其他人已经指出的,您在块的中间声明变量,这仅在 C99 中允许,但在 C89/90 中不允许。也就是说,我们必须得出结论,您正在使用 C99。

其次,您以 K&R 风格(无参数类型)定义函数,但同时稍后不声明参数类型。这样你就依赖于“隐式 int”规则,这在 C99 中是非法的。也就是说,我们必须得出结论,您没有使用C99。这已经和“第一”部分矛盾了。 (此外,习惯上使用无符号类型来表示“对象大小”的概念。size_t是通常用于此目的的专用类型)。

第三,您在 void * 指针上使用指针算术,这在 C89/90 和 C99 中始终是非法的。我什至不知道我们可以从中得出什么结论:)

请决定您要使用的语言,然后我们将从那里开始。

Firstly, as other have already noted, you are declaring variables in the middle of the block, which is only allowed in C99, but not in C89/90. I.e. we have to conclude that you are using C99.

Secondly, you are defining your function in K&R-style (no parameter type), but at the same time not declaring the parameter type later. That way you are relying on the "implicit int" rule, which is outlawed in C99. I.e. we have to conclude that your are not using C99. This is already a contradiction with the "firstly" part. (Additionally, it is customary to use unsigned types to represent the concept of "object size". size_t is a dedicated type normally used for that purpose).

Thirdly, you are using pointer arithmetic on a void * pointer, which is always illegal in both C89/90 and C99. I don't even know what we can conclude from that :)

Please, decide what language you are trying to use, and we will go from there.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文