ç内存分配器及严格别名 [英] C memory allocator and strict aliasing

查看:93
本文介绍了ç内存分配器及严格别名的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

甚至读了不少关于严格走样规则之后,我仍然感到困惑。据我理解这一点,就不可能实现遵循这些规则,一个健全的内存分配,因为的malloc不能重用释放的内存,由于内存可以用来在每个分配存储不同类型的。

显然,这不可能是正确的。我在想什么?如何实现该遵循严格走样分配器(或存储池)?

感谢。

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

  //小号== 0释放池
无效* my_custom_allocator(为size_t S){
    静态无效*池=的malloc(1000);
    静态INT IN_USE = FALSE;
    如果(IN_USE || S> 1000)返回NULL;
    如果(S == 0){
        IN_USE = FALSE;
        返回NULL;
    }
    IN_USE = TRUE;
    返回泳池;
}主(){
    为int * I = my_custom_allocator(的sizeof(INT));
    //使用INT
    my_custom_allocator(0);
    浮* F = my_custom_allocator(的sizeof(浮动)); //不允许...
}


解决方案

我不认为你是对的。即使是最严格的严格别名规则时内存实际分配的目的将只算。一旦分配块已被释放回堆与免费,应该有它的引用,它可以通过的malloc再次给出了

以及无效* 的malloc 返回不受严格走样规则,因为标准中明确规定,一个空指针可以转换成任何其他类型的指针(和回来)。 C99部分7.20.3规定:


  

的指针返回,如果分配成功适当对齐,使得它可以被分配给一个指向任何类型的对象,然后用于访问这样的对象或这样的物体的在分配的空间的阵列(直到空间是显式释放)。



在那里你的您的更新(例子)的条款不的实际回报内存回堆,我觉得你的困惑的产生是因为分配的对象被特殊处理。如果您参考 6.5 / 6 C99,你看:


  

有其存储的值的访问的有效类型的一个对象是该对象的声明的类型,如果有的话。(脚注75:分配对象没有声明的类型)


重新读了注脚,这是非常重要的。


  

如果一个值被存储到一个对象具有带类型不是字符类型,那么左值的类型成为了访问和该做后续访问的有效对象的类型通过左值没有声明的类型不要修改存储的值。


  
  

如果一个数值被复制到一个对象有使用的memcpy或memmove与任何声明的类型,或者被复制为字符类型的数组,则有效类型的访问和不修改的后续访问修改的对象值是有效类型从该值将被复制的对象,如果它有一个。


  
  

有关的所有其他的访问不具有声明类型的对象中,有效的对象的类型是简单地用于接入左值的类型。


在换句话说,分配的内存块的内容会的变成的类型,你把在那里的数据项。

如果你把一个浮动在那里,你应该只访问作为浮动(或兼容型) 。如果你把一个 INT ,你应该只处理它作为一个 INT (或兼容型)。

您的的一件事不应该的做的就是把一个特定类型的变量入内存,然后尝试把它作为不同类型的 - 原因存在一个对象可以有陷阱重新presentations(这会导致不确定的行为),这些重新presentations可能因治疗相同的对象不同类型的发生。

所以,如果你在那里你code中的释放之前存储的 INT ,然后重新分配它作为一个浮动指针,你应该的的尝试使用浮动,直到你真正把一个在那里。直到这一点,分配的类型还不浮动

even after reading quite a bit about the strict-aliasing rules I am still confused. As far as I have understood this, it is impossible to implement a sane memory allocator that follows these rules, because malloc can never reuse freed memory, as the memory could be used to store different types at each allocation.

Clearly this cannot be right. What am I missing? How do you implement an allocator (or a memory pool) that follows strict-aliasing?

Thanks.

Edit: Let me clarify my question with a stupid simple example:

// 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...
}

解决方案

I don't think you're right. Even the strictest of strict aliasing rules would only count when the memory is actually allocated for a purpose. Once an allocated block has been released back to the heap with free, there should be no references to it and it can be given out again by malloc.

And the void* returned by malloc is not subject to the strict aliasing rule since the standard explicitly states that a void pointer can be cast into any other sort of pointer (and back again). C99 section 7.20.3 states:

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).


In terms of your update (the example) where you don't actually return the memory back to the heap, I think your confusion arises because allocated object are treated specially. If you refer to 6.5/6 of C99, you see:

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).

Re-read that footnote, it's important.

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.

In other words, the allocated block contents will become the type of the data item that you put in there.

If you put a float in there, you should only access it as a float (or compatible type). If you put in an int, you should only process it as an int (or compatible type).

The one thing you shouldn't do is to put a specific type of variable into that memory and then try to treat it as a different type - one reason for this being that objects are allowed to have trap representations (which cause undefined behaviour) and these representations may occur due to treating the same object as different types.

So, if you were to store an int in there before the deallocation in your code, then reallocate it as a float pointer, you should not try to use the float until you've actually put one in there. Up until that point, the type of the allocated is not yet float.

这篇关于ç内存分配器及严格别名的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆