【发布时间】:2018-03-10 19:55:35
【问题描述】:
这是一个简短的 C 程序,它提示用户输入一个数字,创建一个由该大小的 int 组成的可变长度数组,然后使用指针算法遍历已分配的元素:
#include <stdio.h>
int main() {
/* Read a size from the user; inhibits compiler optimizations. */
int n;
scanf("%d", &n); // Yes, I should error-check. :-)
/* We now have a VLA. */
int arr[n];
/* What is the type of &arr? */
void* ptr = (&arr) + 1;
/* Seems like this skipped over things properly... */
printf("%p\n", arr);
printf("%p\n", ptr);
}
如果您愿意,可以试试这个on ideone。输出表明该行
void* ptr = (&arr) + 1;
获取arr 的地址,并以大小感知的方式遍历可变长度数组中的所有n 元素。
如果这不是一个可变长度数组,我会完全适应它的工作原理。编译器会知道arr 的类型(对于一些常量K,它会是int (*) [K]),所以当我们在&arr 上加一时,它可以跳过正确的字节数。
很明显,我们可以在运行时评估(&arr) + 1。编译器将arr 的大小存储在堆栈的某个位置,当我们向(&arr) 添加1 时,它知道加载该大小以计算要跳过多少字节。
但是,我不知道该语言所说的表达式 &arr 的类型是什么。它是否分配了一些静态类型,表明它是一个可变长度数组(类似于int (*) [??])?规范是否说“表达式的类型是int (*) [K],其中K 是在运行时分配给数组的任何大小?”规范是否不允许获取可变长度数组的地址,而编译器恰好允许它?
【问题讨论】:
-
绝对允许形成指向可变长度数组的指针;除此之外,如果你不能这样做,VLA 的 VLA 将无法工作。
-
参见 §6.5.6 第 10 段中的示例
-
它将是一个指向可变长度数组类型的指针。
sizeof运算符评估操作数以确定可变长度数组对象的大小,因此+必须做同样的事情。参见 C.2011 - 6.5.6/10。 -
@savram 我的问题不是关于它是如何工作的——机制对我来说很清楚——更多的是关于 C 规范如何将类型分配给这里的表达式。我不认为分解东西会提供任何额外的洞察力。
标签: c pointers language-lawyer variable-length-array