GCC如何实现可变长度数组?

GCC如何实现可变长度数组(VLA)? 这样的数组本质上是指向dynamic分配的存储,如由alloca返回?

我能想到的另一种方法就是将这样一个数组作为函数中的最后一个variables进行分配,以便在编译期间知道variables的偏移量。 然而,第二个VLA的偏移在编译期间再次不被知道。

以下是从以下用于支持VLA的GCC文档中获取的示例代码的分配代码(x86 – x64代码相似):

 char str[strlen (s1) + strlen (s2) + 1]; 

其中strlen (s1) + strlen (s2) + 1的计算在eax (GCC MinGW 4.8.1 – 无优化):

 mov edx, eax sub edx, 1 mov DWORD PTR [ebp-12], edx mov edx, 16 sub edx, 1 add eax, edx mov ecx, 16 mov edx, 0 div ecx imul eax, eax, 16 call ___chkstk_ms sub esp, eax lea eax, [esp+8] add eax, 0 mov DWORD PTR [ebp-16], eax 

所以它看起来基本上是alloca()

那么,根据VLA的限制,这些只是在黑暗中的一些野生刺伤,但无论如何:

VLA的不能是:

  • EXTERN
  • 结构成员
  • 静态的
  • 用未指定的边界声明(除了函数原型)

所有这些都指向VLA被分配到栈上 ,而不是堆。 所以,是的,VLA可能是分配新块时分配的堆栈内存的最后一个块( block的范围内 ,这些是循环,函数,分支或其他)。
这也是为什么VLA会增加堆栈溢出的风险,在某些情况下(例如,警告:甚至不要考虑将VLA与recursion函数调用结合使用)。
这也是为什么越界访问很可能导致问题的原因:一旦块结束,任何指向VLA内存的东西都指向无效内存。
但是从另一方面来说 :这也是为什么这些数组是线程安全的,尽pipe(由于线程有自己的堆栈),为什么它们比堆内存更快。

VLA的大小不能是:

  • 一个extern价值
  • 零或负面

extern限制是非常明显的,非零非负数也是如此…但是:如果指定VLA大小的variables是带符号的int,则编译器不会产生错误:VLA的评估和分配在运行时完成,而不是编译时。 因此VLA的大小不能,在编译期间也不一定是给定的
正如MichaelBurr正确地指出的那样,VLA与alloca内存非常相似,其中一个,恕我直言,关键区别在于:由alloca分配的内存从分配的angular度来看是有效的,在整个函数的其余部分都是有效的。 VLA是块范围的,所以一旦退出使用VLA的块,就会释放内存:

 void alloca_diff( void ) { char *alloca_c, *vla_c; for (int i=1;i<10;++i) { char *alloca_mem = alloca(i*sizeof(*alloca_mem)); alloca_c = alloca_mem;//valid char vla_arr[i]; vla_c = vla_arr;//invalid }//end of scope, VLA memory is freed printf("alloca: %c\n", *alloca_c);//fine printf("vla: %c\n\", *vla_c);//undefined behaviour... avoid! }//end of function alloca memory is freed, irrespective of block scope