14

看这个问题:为什么 C/C++ 编译器需要在编译时知道数组的大小?我想到编译器实现者现在应该有一些时间来涉足(这是 10 年前的 C99 标准的一部分)并提供有效的实现。

然而,它似乎(从答案)仍然被认为是昂贵的。

这不知何故让我感到惊讶。

当然,我知道静态偏移在性能方面比动态偏移要好得多,并且与一个建议不同,我实际上不会让编译器执行数组的堆分配,因为这可能会花费更多[这没有被测量了;)]

但我仍然对假定的成本感到惊讶:

  • 据我所知,如果函数中没有 VLA,那么就不会有任何成本。
  • 如果只有一个 VLA,那么可以将它放在所有变量之前或之后,因此可以获得大部分堆栈帧的静态偏移量(或者在我看来,但我并不精通堆栈管理)

当然,多个 VLA 的问题出现了,我想知道是否有一个专用的 VLA 堆栈会起作用。这意味着 VLA 将由一个计数和一个指针(因此具有已知大小)表示,并且在辅助堆栈中占用的实际内存仅用于此目的(因此实际上也是一个堆栈)。

[改写]

VLA 如何在 gcc / VC++ 中实现?

成本真的那么可观吗?

[结束改写]

在我看来vector,即使使用当前的实现,它也只能比使用 a 更好,因为您不会产生动态分配的成本(以不可调整大小为代价)。

编辑:

这里有部分回应,但是将 VLA 与传统阵列进行比较似乎不公平。如果我们事先知道尺寸,那么我们就不需要 VLA。在同一个问题中,AndreyT 给出了一些关于实现的指示,但它并不像我想要的那样精确。

4

2 回答 2

4

VLA 如何在 gcc / VC++ 中实现?

AFAIK VC++ 没有实现 VLA。它是一个 C++ 编译器,仅支持 C89(无 VLA,无限制)。我不知道 gcc 如何实现 VLA,但最快的方法是将指向 VLA 的指针及其大小存储在堆栈帧的静态部分中。这样,您可以访问具有恒定大小数组性能的 VLA 之一(如果堆栈像 x86 中那样向下增长,它是最后一个 VLA(取消引用 [堆栈指针 + 索引 * 元素大小 + 最后临时推送的大小]),以及第一个 VLA(如果它向上增长)(取消引用 [stackframe 指针 + 与 stackframe 的偏移量 + 索引*元素大小]))。所有其他 VLA 将需要再进行一次间接处理才能从堆栈的静态部分获取它们的基地址。

[编辑:此外,当使用 VLA 时,编译器不能省略 stack-frame-base 指针,否则这是多余的,因为可以在编译时计算堆栈指针的所有偏移量。这样您就少了一个免费注册机。—结束编辑]

成本真的那么可观吗?

并不真地。而且,如果你不使用它,你就不用付钱。

[编辑:可能更正确的答案是:与什么相比?与堆分配的向量相比,访问时间相同,但分配和释放会更快。—结束编辑]

于 2010-12-03T22:55:21.170 回答
0

如果要在 VC++ 中实现,我会假设编译器团队会使用_alloca(size). 而且我觉得代价相当于在栈上使用大于8字节对齐的变量(比如__m128);编译器必须将原始堆栈指针存储在某处,对齐堆栈需要一个额外的寄存器来存储未对齐的堆栈。

所以开销基本上是一个额外的间接(你必须将 VLA 的地址存储在某处)和由于在某处存储原始堆栈范围而导致的寄存器压力。

于 2010-12-03T23:40:07.400 回答