【问题标题】:How is the size of a variable length array computed at runtime in C99?C99 在运行时如何计算可变长度数组的大小?
【发布时间】:2012-12-04 05:02:35
【问题描述】:

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

那么它是如何计算出来的呢?

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

【问题讨论】:

    标签: c arrays c99 variable-length-array ansi-c


    【解决方案1】:

    VLA 和您通过指针变量持有的malloced 数组(除了位于内存的不同部分)之间的区别在于编译器在编译时知道第一个是数组。它可以与 VLA 一起在某个地方保存大小信息,所以基本上这是某种隐藏变量。根据您对该变量的使用情况,例如,如果您使用sizeof,或者如果您通过A[i][j] 之类的东西索引二维VLA,那么编译器可以决定是否真的需要该隐藏变量,如果不需要,优化一下。

    【讨论】:

    • 通俗易懂!谢谢。抱歉 11rep 我不能为你 +1。
    【解决方案2】:

    来自 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
    }
    

    【讨论】:

    猜你喜欢
    • 2015-12-18
    • 2017-05-17
    • 2012-01-29
    • 2017-05-01
    • 1970-01-01
    • 2011-12-13
    • 2017-09-25
    • 2018-11-07
    • 2014-08-16
    相关资源
    最近更新 更多