C内存分配器和严格别名

Seb*_*nde 8 c memory-management strict-aliasing language-lawyer

即使在阅读了相当多的严格别名规则后,我仍然感到困惑.据我所知,不可能实现遵循这些规则的合理的内存分配器,因为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...
}
Run Code Online (Sandbox Code Playgroud)

pax*_*blo 9

我不认为你是对的.即使是最严格的严格别名规则也只会在实际为某个目的分配内存时计算.一旦分配的块被释放回堆中free,就不应该对它进行引用,它可以再次发出malloc.

void*通过返回malloc,因为标准中明确规定,一个空指针可以转换成任何其他类型的指针(和回来)是不受严格别名规则.C99第7.20.3节规定:

如果分配成功,则返回的指针被适当地对齐,以便可以将其指定给指向任何类型对象的指针,然后用于在分配的空间中访问此类对象或此类对象的数组(直到空间被显式释放) .


就你没有实际将内存返回堆的更新(例子)而言,我认为你的混乱是因为分配的对象被特别处理.如果您参考6.5/6C99,您会看到:

用于访问其存储值的对象的有效类型是对象的声明类型(如果有)(脚注75:已分配的对象没有声明的类型).

重新阅读该脚注,这很重要.

如果通过具有非字符类型的左值的值将值存储到没有声明类型的对象中,则左值的类型将成为该访问的对象的有效类型以及不修改该值的后续访问的有效类型储值.

如果使用memcpy或memmove将值复制到没有声明类型的对象中,或者将其复制为字符类型数组,则该访问的修改对象的有效类型以及不修改该值的后续访问的有效类型是复制值的对象的有效类型(如果有).

对于没有声明类型的对象的所有其他访问,对象的有效类型只是用于访问的左值的类型.

换句话说,分配的块内容将成为您放在那里的数据项的类型.

如果你放在float那里,你应该只作为float(或兼容的类型)访问它.如果你输入int,你应该只处理int(或兼容类型).

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

所以,如果你要存储一个int在代码中释放之前在那里,然后重新分配它作为一个float指针,你应该尝试使用浮动,直到你居然把一个在那里.到那时为止,分配的类型还没有float.