发布于 ,更新于 

C11 的变长数组

C11 的变长数组

C 语言新版本支持变长的数组(variable length array,简称VLA),数组的长度可以用一个变量来决定。

如果 C 编译器不支持变长数组,那么宏定义 __STDC_NO_VLA__ 就必须定义为 1。使用下面的代码可以检查是否支持变长数组:

1
2
3
4
5
#ifdef __STDC_NO_VLA__

printf("不支持变长数组 \n");

#endif // __STDC_NO_VLA__

代码中有些地方是不能声明和定义为变长数组的:

一、变长数组不能是全局变量
二、extern 外部变量
三、结构或者联合里面的字段
四、static 变量

也就是说,变长数组只能用于非 static 的局部变量。

变长数组的实现原理是什么,下面以一个简单的 .c 程序,进行编译成汇编看看:

1
2
3
4
5
6
7
8
9
10
11
12
13
// varr.c
#include <stdio.h>

static void func1(int arrsize)
{
int array[arrsize]; // 这里定于可变数组,数组的大小由一个变量来决定
}

int main()
{
func1(9);
return 0;
}

用下面命令:

1
gcc -std=c99 -S varr.c

编译为汇编得到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
	.file	"varr.c"
.text
.def _func1; .scl 3; .type 32; .endef
_func1:
pushl %ebp
movl %esp, %ebp
pushl %ebx
subl $20, %esp
movl %esp, %eax
movl %eax, %ecx
movl 8(%ebp), %eax
leal -1(%eax), %edx
movl %edx, -12(%ebp)
leal 0(,%eax,4), %edx
movl $16, %eax
subl $1, %eax
addl %edx, %eax
movl $16, %ebx
movl $0, %edx
divl %ebx
imull $16, %eax, %eax
call ___chkstk_ms
subl %eax, %esp
movl %esp, %eax
addl $3, %eax
shrl $2, %eax
sall $2, %eax
movl %eax, -16(%ebp)
movl %ecx, %esp
nop
movl -4(%ebp), %ebx
leave
ret
.def ___main; .scl 2; .type 32; .endef
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
call ___main
movl $9, (%esp)
call _func1
movl $0, %eax
leave
ret
.ident "GCC: (GNU) 10.2.0"

从上述汇编代码中可以看出,可变数组是根据数组大小的变量,动态地在栈中开辟一串连续的空间,来作为动态数组的存储空间。
函数执行完毕之后,这部分在栈内动态开辟的空间,会自动被回收。