GCC如何实现可变长度数组(VLA)?这些数组是否基本上指向动态分配的存储,例如alloca返回的存储?
我能想到的另一个选择是,这样的数组被分配为函数中的最后一个变量,因此在编译时可以知道变量的偏移量.但是,在编译期间,第二个VLA的偏移量将再次不知道.
以下是从一些GCC文档中获取的用于VLA支持的以下示例行的分配代码(x86 - x64代码类似):
char str[strlen (s1) + strlen (s2) + 1];
Run Code Online (Sandbox Code Playgroud)
其中的计算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
Run Code Online (Sandbox Code Playgroud)
所以它看起来基本上是alloca().
嗯,根据VLA周围的限制,这些只是在黑暗中的一些野生刺,但无论如何:
VLA不能是:
所有这些都指向VLA被分配在堆栈上,而不是堆.所以是的,VLA可能是分配新块时分配的堆栈内存的最后一块(块作用在块作用域中,这些是循环,函数,分支或其他).
这也是为什么VLA会增加堆栈溢出的风险,在某些情况下会显着增加(警告:例如,甚至不考虑将VLA与递归函数调用结合使用!).
这也是为什么出界外的访问是很容易造成的问题:一旦块结束时,任何指向什么当时 VLA内存,指向无效的内存.
但另一方面:这也是为什么这些数组是线程安全的(因为线程有自己的堆栈),以及为什么它们比堆内存更快.
VLA的大小不能是:
extern价值外部限制是非常明显的,非零,非负面限制......但是:例如,如果指定VLA大小的变量是带符号的int,则编译器不会产生错误:VLA的评估和分配是在运行时完成的,而不是编译时完成的.因此,VLA的大小不能,也不需要在编译时给定.
正如MichaelBurr正确地指出的那样,VLA与alloca内存非常相似,其中一个是恕我直言,这是一个至关重要的区别:分配的内存在分配alloca点和整个函数的其余部分都是有效的.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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5920 次 |
| 最近记录: |