首页 > 解决方案 > 了解处理可变长度数据,特别关注 C(99) 中的可变长度数组

问题描述

以下是红龙书的节选。它处理过程激活记录中可变长度数据项的处理。

Pascal在语言中几乎是独一无二的,它要求过程本地的数组具有可以在编译时确定的长度。更常见的是,本地数组的大小可能取决于传递给过程的参数值。在这种情况下,在调用过程之前,无法确定过程本地的所有数据的大小。

图 7.15 建议了处理可变长度数据的常用策略,其中过程p具有三个局部数组。这些数组的存储不是 ; 的激活记录的一部分p。只有一个指向每个数组开头的指针出现在激活记录中。这些指针的相对地址在编译时是已知的,因此目标代码可以通过指针访问数组元素。

数字

图 7.15 还显示了一个q由 调用的过程p。的激活记录q在 的数组之后开始p,而可变长度的数组在此之后q开始。

在上面摘录的第一部分中,文本讨论了Pascal编程语言的特性,然后他们讨论了相同的可能实现。现在我不熟悉Pascal并想了解这种情况的处理方式C

我知道可以C使用malloc及其姊妹函数动态创建数组,这会导致在堆上分配内存,并将指向第一个字节的指针返回给我们。根本不是问题。

如果我们创建数组,C其中数组的大小是一个常量,如下所示:

int function() {
   int a[100];
  }

然后将该数组放置在local data如下所示的激活记录部分中:

激活记录

在上面的例子中,数组的大小a在编译时就知道了。没有问题。

现在的情况:“更多时候,本地数组的大小可能取决于传递给过程的参数值。在这种情况下,直到调用过程才能确定过程本地的所有数据的大小。 "

情况1:

现在让我们考虑下面的代码:

  int function(int n){
           int a[n];
  }
  int main() {
        function(10);
  }

现在在上面的情况下,参数的大小n可以function在编译时知道,因此数组的大小a虽然变量可以在编译时知道。有了这个逻辑C,上面的数组是不是按照龙书a里的方式分配?fig 7.15

案例二:

  int function(int n){
           int a[n];
  }
  int main() {
        int x;
        scanf("%d",&x);
        function(x);
  }

现在在上面的情况下,参数的大小n只能function在运行时知道(?)还是仍然是上面的情况,即在编译时知道?现在在这段代码中,数组a分配在哪里。堆还是栈?

我去了这里这里这里,但没有找到我正在寻找的解释......


这里我说的是C99

标签: arrayscompiler-constructionc99variable-length-arrayruntime-environment

解决方案


通常,C 实现在堆栈上分配 VLA,而不是在单独的堆数据结构中,但这实际上并不是标准所要求的。由于 VLA 的大小仅在运行时才知道,这意味着您可以获得此类函数的可变大小的激活记录。激活记录如何分配和布局的细节往往取决于目标机器及其 ABI,因此尝试将其分解(如上图所示)对于不同的编译器和架构会有很大的不同。


推荐阅读