有没有一种方法可以检查变长数组是在堆栈上还是堆上创建的?

3

据我所理解,以下代码使用C++的一个非标准扩展生成变长数组。

int main() 
{
    int valone = rand();
    int valtwo = rand();
    int array[valone][valtwo];
    // Printing size
    cout << sizeof(array) << endl;
}

有没有办法检查它是在堆栈还是堆上生成的?维基百科这里的描述说,gcc在堆栈中生成相同的内容,但是当我尝试以上代码时,大多数情况下,数组大小似乎太大而无法适应堆栈,但它从未抱怨过。
注意:此代码仅适用于gcc和clang,不适用于Visual Studio。

你指向的维基百科链接讨论的是C99,而不是C++。gcc可能会将C99代码和C++代码视为同一种。 - R Sahu
3
虽然“标准”并不适用于“非标准扩展”,但如果你想快速测试,可以比较valtwoarray[0]的地址。如果数组在堆栈上,它们应该是相邻的。如果在堆上,它们会有很大的不同。这不是100%可靠的,但大多数情况下都有效。 - Mikhail
直到你访问临时存储之外的内容,它可能不会抱怨,但谁能确定呢? - user4581301
请参见https://dev59.com/HWYr5IYBdhLWcg3wYZSD#13720219。 - Mikhail
请注意,堆栈溢出的情况并不总是显而易见的,特别是如果您从未写入数组末尾的项目(甚至可能即使您这样做也不会)。因此,“它从不抱怨”这一事实不应被视为有关非标准扩展实现的任何迹象。 - Jeremy Friesner
显示剩余2条评论
3个回答

1
这可能是一个棘手的问题,我尝试过一些类似的东西。
#include "iostream"

int Stack_or_heap(void* ptr)
{
 int dummy;
 return ptr > &dummy;
}

int main(int argc, char** argv)
{
   int* i = new int();
   int x, y, z;
   std::cout << Stack_or_heap(&x) << Stack_or_heap(&y) << Stack_or_heap(&z) << Stack_or_heap(i);
}

这不仅非常可靠,而且聪明,这个想法可能足以满足op的需求。在op的情况下,您可以直接在数组附近使用int,并检查数组和int的地址是否相近。 - WorldSEnder

1

数组大小似乎太大而无法放入堆栈,但它从未抱怨。

通过“从未抱怨”,我认为您的意思是程序不会崩溃。

您从未触及分配的内存,编译器足够聪明以证明并未分配任何内容。

让我们获取该变量的地址,并将其发送到在其他地方定义的函数中:

int array[valone][valtwo] = {};
cout << &array << endl;

现在,编译器并不确定数组是否被访问。这是因为它无法进入另一个翻译单元中实现的流操作符。也许操作符会解引用指针,我们必须确保数组存在。
第一次尝试时,该程序由于堆栈溢出而崩溃了。
我想这种崩溃测试是为了测试VLA是否在堆栈上。
Mikhail在评论中建议比较自动变量的邻近性和VLA,这是一个相当好的平台相关的想法,但只有在分配的VLA足够小以避免程序崩溃时才能起作用。

0

首先,我假设您知道使用malloc或new在堆中分配的任何内存块都会在整个程序的生命周期内保持其存在,除非显式释放。因此,我们可以得出结论,如果变长数组仅存在于其作用域中而不在程序的生命周期中,则最有可能在堆栈中分配。

我不知道是否存在一些情况,其中一块内存在堆中分配,但表现得像是堆栈的成员。最好查看汇编代码。这种实现可能在幕后使用动态分配函数/系统调用。

如果它看起来像鸭子,走路像鸭子,说话像鸭子,那么可以安全地假设它是鸭子(大多数情况下)。


1
我认为你在第一段的推理是有缺陷的。如果一个内存块可以被隐式地分配,那么这个隐式分配的块也可以被隐式地释放。完全有可能使用malloc来实现VLA。 - eerorika
这可能是原因,这也是为什么在第二段中我说我不知道是否存在这样的情况,即分配发生在堆中,但表现为堆栈的成员。另一种推理方式是在堆栈中分配的任何内容都是在编译时确定的。对于VLAs而言,这并非总是正确的。据我所知,任何在运行时分配的内容都必须在堆中进行分配。因此,我们面临一个两难境地,即分配需求要求将空间分配到堆中,因为它在运行时解决,但通过作用域规则表现得像是堆栈的成员。 - nmd_07
我认为真正的检查需要知道虚拟地址空间中的堆地址空间。 - nmd_07

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接