VLA(Variable Length Array)是c99开始支持的,后续版本一直作为扩展功能支持。官方给出的建议是:如果可以替换使用,请不要使用。因为当变量过大,会直接导致栈空间溢出失败。
一般常见的替换方法:
1)限制N的大小,并添加检查;2)使用动态数据结构替换,如std::vector;3)使用new/malloc等申请内存。
对于VLA的实现,底层是如何进行栈空间内存的申请,下面我们来看一个实例:
void vla(int size) {
int a[size];
}
通过clang进行编译,dump出llvm ir的信息: clang -S -emit-llvm -o 目标文件 源文件
define dso_local void @vla(int)(i32 noundef %0) #0 !dbg !362 {
%2 = alloca i32, align 4
%3 = alloca ptr, align 8
%4 = alloca i64, align 8
store i32 %0, ptr %2, align 4
call void @llvm.dbg.declare(metadata ptr %2, metadata !367, metadata !DIExpression()), !dbg !368
%5 = load i32, ptr %2, align 4, !dbg !369
%6 = zext i32 %5 to i64, !dbg !370
%7 = call ptr @llvm.stacksave(), !dbg !370
store ptr %7, ptr %3, align 8, !dbg !370
%8 = alloca i32, i64 %6, align 16, !dbg !370
store i64 %6, ptr %4, align 8, !dbg !370
call void @llvm.dbg.declare(metadata ptr %4, metadata !371, metadata !DIExpression()), !dbg !373
call void @llvm.dbg.declare(metadata ptr %8, metadata !374, metadata !DIExpression()), !dbg !378
%9 = load ptr, ptr %3, align 8, !dbg !379
call void @llvm.stackrestore(ptr %9), !dbg !379
ret void, !dbg !379
}
指令%8 = alloca i32, i64 %6, align 16, !dbg !370 便是用于栈空间内存申请的处理,alloca指令的主要功能为:alloca
: This is an LLVM instruction that allocates memory on the stack dynamically. The memory allocated by alloca
is automatically freed when the function that called alloca
returns. It's similar to variable-length arrays in C. (GPT结果)
此外,@llvm.stacksave() 和 @llvm.stackrestore(ptr %9)便是栈上用来保存和读取对应指针的处理动作。