如何在C99运行时计算可变长度数组的大小?

在C89中,数组的长度在编译时是已知的。 但在C99中,对于可变长度数组,数组的长度在运行时可能是未知的。

那怎么计算呢?

为什么不能以相同的方式计算动态分配的数组的长度?

来自ISO / IEC 9899:TC3第6.7.5.2节:数组声明符

具有可变修改类型的普通标识符(如6.2.3中所定义) 应具有块范围和无链接或函数原型范围。 如果标识符被声明为具有静态存储持续时间的对象,则它不应具有可变长度数组类型。

VLA的大小只是sizeof(vla_element_type) * vla_length 。 由于VLA只能在块中定义,因此its length must be either a local variable or a function parameter ,当访问vla时,编译器可以访问它。 (由于vla的长度和vla本身属于同一堆栈帧)。

 Here is an example: int main(int argc, char* argv[]) { int m; scanf("%d\n", &m); int a[m]; printf("%d\n", sizeof(a)); return 0; } 

clang -o test.ll -O2 -emit-llvm -S test.c编译,生成的IR如下所示:

 define i32 @main(i32 %argc, i8** nocapture %argv) nounwind { entry: // Allocate space on stack for m %m = alloca i32, align 4 // call scanf %call = call i32 (i8*, ...)* @__isoc99_scanf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i32* %m) nounwind // %0 now contains the value of m %0 = load i32* %m, align 4, !tbaa !0 // %1 is m << 2, which is m * sizeof(int) %1 = shl nuw i32 %0, 2 // call printf, output m * sizeof(int) to screen. %call1 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([4 x i8]* @.str, i32 0, i32 0), i32 %1) nounwind // DONE. ret i32 0 } 

通过指针变量保存的VLA和malloc ed数组之间的区别(除了生活在内存的不同部分之外)是编译器在编译时知道第一个是数组。 它可以在VLA的某个位置保存大小信息,所以基本上这是一些隐藏的变量。 根据您对该变量的使用情况,例如,如果您使用sizeof ,或者通过A[i][j]之类A[i][j]东西索引2D VLA,则编译器可以确定是否确实需要该隐藏变量,并且,如果没有,优化它。