这是一个简短的C程序,提示用户输入一个数字,创建一个长度可变的整数数组,并使用指针算术运算来跨越已分配的元素:
#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);
}
如果您愿意,可以在ideone上尝试此代码。输出结果表明该行
void* ptr = (&arr) + 1;
将arr
的地址以一种大小感知的方式传递,并遍历可变长度数组中的所有n
个元素。
如果这不是一个可变长度数组,我对它的工作原理完全感到满意。编译器将知道arr
的类型(对于某个常量K
,它将是int (*) [K]
),因此当我们将&arr
加1时,它可以跳过正确数量的字节。
很明显,在运行时,我们如何评估(&arr) + 1
。编译器将arr
的大小存储在堆栈的某个位置上,当我们将(&arr)
加1时,它知道加载该大小以计算要跳过多少字节。
然而,我不知道语言规范如何描述表达式&arr
的类型。它是否分配了某些静态类型,指示它是可变长度数组(类似于int (*) [??]
)?规范是否说“表达式的类型为int (*) [K]
,其中K
是在运行时分配给数组的任何大小”?规范是否禁止获取可变长度数组的地址,而编译器只是偶然允许它?
sizeof
运算符评估操作数以确定可变长度数组对象的大小,因此+
必须执行相同的操作。请参见C.2011 - 6.5.6/10。 - jxh