简体   繁体   English

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

[英]How is the size of a variable length array computed at runtime in C99?

In C89, the length of an array is known at compile time. 在C89中,数组的长度在编译时是已知的。 But in C99, with variable length arrays, the length of an array may be unknown before runtime. 但是在C99中,对于可变长度数组,在运行之前,数组的长度可能是未知的。

So how does it get computed? 那怎么计算呢?

And why couldn't the length of a dynamically allocated array be computed in the same way? 为什么不能以相同的方式计算动态分配的数组的长度?

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

An ordinary identifier (as defined in 6.2.3) that has a variably modified type shall have either block scope and no linkage or function prototype scope. 具有可变修改类型的普通标识符(如6.2.3中所定义) 应具有块范围,无链接或函数原型范围。 If an identifier is declared to be an object with static storage duration, it shall not have a variable length array type. 如果标识符被声明为具有静态存储持续时间的对象,则它不应具有可变长度数组类型。

The sizeof a VLA is simply sizeof(vla_element_type) * vla_length . VLA的大小只是sizeof(vla_element_type) * vla_length Since a VLA can only be defined within a block, its length must be either a local variable or a function parameter , which can be accessed by the compiler when the vla is accessed. 由于VLA只能在块中定义,因此its length must be either a local variable or a function parameter ,当访问vla时,编译器可以访问它。 (Since the length of vla and the vla itself belongs to the same stack frame). (由于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;
}

Compiled with clang -o test.ll -O2 -emit-llvm -S test.c , the generated IR is shown as follows: 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
}

The difference between a VLA and a malloc ed array that you hold through a pointer variable (besides living in different parts of the memory) is that the compiler knows at compile time that the first is an array. 通过指针变量保存的VLA和malloc ed数组之间的区别(除了存在于内存的不同部分之外)是编译器在编译时知道第一个是数组。 It can hold the size information(s) in some place along with the VLA, so basically this is some sort of hidden variable(s). 它可以在VLA的某个位置保存大小信息,所以基本上这是一些隐藏的变量。 Depending on the usage that you do with that variable, if eg you use sizeof with it or if you index a 2D VLA through something like A[i][j] the compiler can then decide if that hidden variable is really needed, and, if not, optimize it out. 根据您对该变量的使用情况,例如,如果您使用sizeof或者通过A[i][j]之类A[i][j]东西索引2D VLA,则编译器可以确定是否确实需要该隐藏变量,并且,如果没有,优化它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM