了解堆栈分配的对象释放

St.*_*rio 3 c arrays memory-management

我试图理解堆栈分配对象的解除分配行为.确切地说,我试图在标准中找到解释(N1570).考虑以下简单功能:

void foo(){
    char test[4096];
    test[10] = 0;
}
Run Code Online (Sandbox Code Playgroud)

退出test时,数组将被释放foo.很容易看出,objdump它test是在堆栈上分配的.标准(强调我的)说明:

声明标识符没有链接且没有存储类说明符静态的对象具有自动存储持续时间,一些复合文字也是如此.

所以test有自动存储时间.我们可以轻松地重写函数如下:

void test(){
    char *test= malloc(4096 * sizeof(char));
    test[10] = 0;
    free(test);
}
Run Code Online (Sandbox Code Playgroud)

但我们必须自己解除分配,但test仍然有自动存储时间.

问题:标准如何指定char test[4096]将在函数退出时释放?标准没有声明test在堆栈上分配,它是实现定义的.

Sto*_*ica 6

该标准描述了§6.2.4中的各种存储持续时间

1对象具有确定其生命周期的存储持续时间.有四个存储持续时间:静态,线程,自动和已分配.分配的存储在7.22.3中描述.

2对象的生命周期是程序执行的一部分,在此期间保证为其保留存储.存在一个对象,具有一个常量地址,并在其整个生命周期内保留其最后存储的值.如果在其生命周期之外引用对象,则行为未定义.当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针的值变得不确定.

6对于没有可变长度数组类型的对象,其生命周期从entry进入与其关联的块,直到该块的执行以任何方式结束.(输入一个封闭的块或调用一个函数暂停,但不会结束,执行当前块.)如果以递归方式输入块,则每次都会创建一个新的对象实例.对象的初始值是不确定的.如果为对象指定了初始化,则每次在执行块时达到声明或复合文字时都会执行初始化; 否则,每次达到声明时,该值将变为不确定.

所以你非常正确.它根本没有描述存储器本身何时以及如何解除分配.它仅指定何时可以使用定义明确的语义访问该存储.实现不需要立即释放具有自动存储持续时间的变量的存储,如果您希望程序符合标准,则无法触摸它.

对于分配的存储,情况也是如此,增加的警告是,您必须明确告知实现存储的完成情况.但是,即使你"免费"它,一个实现可能会持续一段时间.

在纸面上可能存在非常差的实现,一个永远不会释放内存的实现.但在实践中,这些被自然地剔除,因为C的不良实施只会被群众废弃而被抛弃.

  • @ St.Antario - 不是`test`,而是`*test`.指针具有自动存储持续时间.*pointee*已分配持续时间.它可能看起来像分裂头发,但是一个重要的区别. (2认同)