C 内存分配器和严格的别名

标签 c memory-management language-lawyer strict-aliasing

即使在阅读了很多有关严格别名规则的内容之后,我仍然感到困惑。据我所知,不可能实现遵循这些规则的合理内存分配器,因为 malloc 永远无法重用释放的内存,因为内存可用于在每次分配时存储不同类型。

显然这是不对的。我错过了什么?如何实现遵循严格别名的分配器(或内存池)?

谢谢。

编辑: 让我用一个愚蠢的简单例子来澄清我的问题:

// s == 0 frees the pool
void *my_custom_allocator(size_t s) {
    static void *pool = malloc(1000);
    static int in_use = FALSE;
    if( in_use || s > 1000 ) return NULL;
    if( s == 0 ) {
        in_use = FALSE;
        return NULL;
    }
    in_use = TRUE;
    return pool;
}

main() {
    int *i = my_custom_allocator(sizeof(int));
    //use int
    my_custom_allocator(0);
    float *f = my_custom_allocator(sizeof(float)); //not allowed...
}

最佳答案

我不认为你是对的。即使是最严格的严格别名规则也只会在内存实际分配用于某个目的时才算数。一旦使用 free 将分配的 block 释放回堆中,就不会再有对它的引用,它可以通过 malloc 再次给出。

并且 malloc 返回的 void* 不受严格的别名规则的约束,因为标准明确指出 void 指针可以转换为任何其他类型的指针(然后再回来)。 C99 第 7.20.3 节指出:

The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated).


就您实际上将内存返回堆的更新(示例)而言,我认为您会产生混淆,因为分配的对象被特殊对待。如果你引用 C99 的 6.5/6,你会看到:

The effective type of an object for an access to its stored value is the declared type of the object, if any (footnote 75: Allocated objects have no declared type).

重新阅读脚注,这很重要。

If a value is stored into an object having no declared type through an lvalue having a type that is not a character type, then the type of the lvalue becomes the effective type of the object for that access and for subsequent accesses that do not modify the stored value.

If a value is copied into an object having no declared type using memcpy or memmove, or is copied as an array of character type, then the effective type of the modified object for that access and for subsequent accesses that do not modify the value is the effective type of the object from which the value is copied, if it has one.

For all other accesses to an object having no declared type, the effective type of the object is simply the type of the lvalue used for the access.

换句话说,分配的 block 内容将成为您放入其中的数据项的类型。

如果您在其中放置一个float,您应该只将它作为float(或兼容类型)访问。如果您输入一个 int,您应该只将它作为一个 int(或兼容类型)处理。

不应该做的一件事是将特定类型的变量放入该内存中,然后尝试将其视为不同的类型 - 这样做的一个原因是允许对象具有陷阱表示(这会导致未定义的行为),并且这些表示可能是由于将同一对象视为不同类型而发生的。

因此,如果您要在代码中的释放之前将 int 存储在那里,然后将其重新分配为 float 指针,您应该 尝试使用 float ,直到你真正把一个 float 放在那里。到那时,分配的类型还不是float

关于C 内存分配器和严格的别名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7687082/

相关文章:

c - 包含 char 的 C 结构的大小

c++ - using namespace std 的排序;包括?

c - 我们不能用指针进行什么操作?

c - GPS代码不读取纬度数据

在 C 中检查链表是否为空

c - 在 C 字符串中包含双引号 (")

c - 字符串比较失败

C++ std::make_shared 内存泄漏

c++ - 函数重新分配 c 字符串后 delete[] 时出现无效指针错误

c++ - std::initializer_list可以专用吗?