C和C++;在堆栈上存储大型对象? 我试图弄清楚C和C++如何在堆栈上存储大对象。通常,堆栈的大小是整数,所以我不知道较大的对象是如何存储在那里的。它们只是占用多个堆栈“插槽”吗?

C和C++;在堆栈上存储大型对象? 我试图弄清楚C和C++如何在堆栈上存储大对象。通常,堆栈的大小是整数,所以我不知道较大的对象是如何存储在那里的。它们只是占用多个堆栈“插槽”吗?,c++,c,memory,stack,C++,C,Memory,Stack,通过“堆栈是整数的大小”,您的意思是“堆栈指针是整数的大小”。它指向堆栈的顶部,这是一个巨大的内存区域。嗯,大于整数。您可以拥有足够大(或足够多)的对象,以至于将它们放在堆栈上没有意义。在这种情况下,您可以将对象放在堆上,并将指向它的指针放在堆栈上。这是“按值传递”和“按引用传递”之间的差异。如何定义大型对象?我们说的是大于还是小于分配的堆栈空间的大小 例如,如果您有如下内容: void main() { int reallyreallybigobjectonthestack[10000

通过“堆栈是整数的大小”,您的意思是“堆栈指针是整数的大小”。它指向堆栈的顶部,这是一个巨大的内存区域。嗯,大于整数。

您可以拥有足够大(或足够多)的对象,以至于将它们放在堆栈上没有意义。在这种情况下,您可以将对象放在堆上,并将指向它的指针放在堆栈上。这是“按值传递”和“按引用传递”之间的差异。

如何定义大型对象?我们说的是大于还是小于分配的堆栈空间的大小

例如,如果您有如下内容:

void main() {
    int reallyreallybigobjectonthestack[1000000000];
}
根据您的系统,您可能会遇到segfault,因为根本没有足够的空间来存储对象。否则它会像其他任何对象一样存储。如果您在实际的物理内存中说话,那么您不必担心这一点,因为操作系统级别的虚拟内存将负责处理这一问题


也不可能是一个整数的大小,它完全取决于你的操作系统和应用程序的布局。在C和C++中,

不应该在堆栈上存储大对象,因为堆栈是有限的(如你所猜测的)。每个线程的堆栈通常只有几兆字节或更少(可以在创建线程时指定)。当您调用“new”来创建对象时,它不会放在堆栈上,而是放在堆上。

堆栈大小是有限的。通常在创建进程时设置堆栈大小。如果在CreateThread()调用中未另行指定,则该进程中的每个线程都会自动获取默认堆栈大小。所以,是的:可以有多个堆栈“插槽”,但每个线程只有一个。而且它们不能在线程之间共享

如果将大于剩余堆栈大小的对象放入堆栈,则会出现堆栈溢出,应用程序将崩溃


因此,如果您有非常大的对象,请在堆上而不是堆栈上分配它们。堆仅受虚拟内存量(比堆栈大一个数量级)的限制。

堆栈是一块内存。堆栈指针指向顶部。可以将值推送到堆栈上并弹出以检索它们

例如,如果我们有一个使用两个参数调用的函数(1字节大小,另2字节大小;假设我们有一台8位PC)

两者都被推到堆栈上,这会将堆栈指针向上移动:

03: par2 byte2
02: par2 byte1
01: par1
现在调用函数并将返回地址放在堆栈上:

05: ret byte2
04: ret byte1
03: par2 byte2
02: par2 byte1
01: par1
函数中有两个局部变量;2个字节中的一个和4个字节中的一个。对于这些,堆栈上保留了一个位置,但首先我们保存堆栈指针,以便通过向上计数知道变量的起始位置,通过向下计数找到参数

11: var2 byte4
10: var2 byte3
09: var2 byte2
08: var2 byte1
07: var1 byte2
06: var1 byte1
    ---------
05: ret byte2
04: ret byte1
03: par2 byte2
02: par2 byte1
01: par1

如您所见,只要还有空间,就可以在堆栈上放置任何内容。否则,您将获得为该站点命名的现象。

每当您输入一个函数时,堆栈将增长以适应该函数中的局部变量。给定一个使用400字节的
largeObject
类:

void MyFunc(int p1, largeObject p2, largeObject *p3)
{
   int s1;
   largeObject s2;
   largeObject *s3;
}
调用此函数时,堆栈的外观如下所示(详细信息将根据调用约定和体系结构而有所不同):

有关堆栈如何操作的一些信息,请参见。
MSDN还为一些不同的调用转换提供了一些很好的图表,包括和。

堆栈是一大块内存,用于存储本地变量、函数调用返回的信息等。堆栈的实际大小在操作系统上差异很大。例如,在Windows上创建新线程时

如果您试图创建一个堆栈对象,该对象需要的内存比当前堆栈上可用的内存多,则会出现堆栈溢出,并发生不好的情况。一大类利用漏洞的代码故意试图创造这些或类似的条件

堆栈没有划分为整数大小的块。它只是一个扁平的字节数组。它由类型为size\u t(非int)的“整数”索引。如果创建一个适合当前可用空间的大型堆栈对象,它将通过向上(或向下)移动堆栈指针来使用该空间

正如其他人指出的,最好对大型对象使用堆,而不是堆栈。这避免了堆栈溢出问题


编辑:如果您使用的是64位应用程序,并且您的操作系统和运行时库对您很好(请参阅mrree的文章),那么在堆栈上分配大型临时对象就可以了。如果您的应用程序是32位的和/或您的操作系统/运行时库不好,您可能需要在堆上分配这些对象。

Push
pop
指令通常不用于存储本地堆栈帧变量。在函数开始时,堆栈帧是通过将堆栈指针递减函数的局部变量所需的字节数(与字大小对齐)来设置的。这将为这些值分配“堆栈上”所需的空间量。然后通过指向此堆栈帧的指针访问所有局部变量(
ebp
在x86上)。

正如其他人所说,不清楚“大对象”是什么意思。。。然而,既然你问

它们只是占用多个堆栈吗 “吃角子老虎”

我假设你只是指大于整数的任何东西。不过,正如其他人所指出的,堆栈没有整数大小的“插槽”——它只是内存的一部分,每个字节都有自己的地址。编译器通过变量的第一个字节的地址跟踪每个变量——这是y
   [... rest of stack ...]
   [4 bytes for p1] 
   [400 bytes for p2]
   [4 bytes for p3]
   [return address]
   [old frame pointer]
   [4 bytes for s1]
   [400 bytes for s2]
   [4 bytes for s3]
pthread_t       threadData;
pthread_attr_t  threadAttributes;

pthread_attr_init( & threadAttributes );
ASSERT_IS( 0, pthread_attr_setdetachstate( & threadAttributes,
                                             PTHREAD_CREATE_DETACHED ) );

ASSERT_IS( 0, pthread_attr_setstacksize  ( & threadAttributes,
                                             128 * 1024 * 1024 ) );

ASSERT_IS( 0, pthread_create ( & threadData,
                               & threadAttributes,
                               & runthread,
                               NULL ) );
struct rlimit  limits;
limits.rlim_cur = RLIM_INFINITY;
limits.rlim_max = RLIM_INFINITY;
ASSERT_IS( 0, setrlimit( RLIMIT_STACK, & limits ) );