大家好,我是李述铜,一名专注于嵌入式系统与底层开发的技术讲师,我的主要工作是制作课程带大家从零手写操作系统、TCP/IP协议栈、文件系统等核心系统,从实现的视角理解计算机底层原理。
今天继续写一写C语言中很实用、但常被忽略的特性——变长数组(Variable Length Array, VLA)。这个特性同样是我在阅读《C Primer Plus》中看到的内容。
在做嵌入式开发时,你是不是也遇到过这种尴尬的问题: 为了存放通信的数据包,需要定义一个数组,然而数组要预分配成MAX_LEN长度。 但是,实际使用时只用了前面几十字节,却硬生生占掉上千字节空间。 而为了节省内存,就只能上malloc(),却还得担心泄漏。 很多时候,我们并不是不会写,而是受限于语言本身。针对该问题,C99标准已经给出了更优雅的解决方案:变长数组(VLA)。 可惜它一直被低估、被忽视,甚至许多工程师压根不知道自己可以用它。今天,我们就来认真说说这个看似不起眼,却能让代码变得又优雅又高效的小能力。
在嵌入式开发中,如果我们要定义一个数组,往往会这样写:
int buf[10];也就是说,在定义数组的时候,会给数组指定好长度。这样一来,数组的长度就在编译期就确定。
不过,在有些情况下,比如协议解析时,数组长度往往是运行时才知道的。比如:
int n;
scanf("%d", &n);
int buf[n]; 在上面的代码中,我们想要根据用户输入的字节数量,来确定分配多大的空间。但是,这段代码在旧版C标准(C89/C90)中会报错,因为数组长度必须是常量表达式。所以,我们可能会预先定义一个最大可能使用的空间。比如:
#define MAX_LEN 1024
int n;
scanf("%d", &n);
int buf[200]; // 按最大的来这种处理方法非常常见,简单有效,但是有时候也会带来一些问题:
有的同学可能会采用动态内存分配,按需分配内存,比如:
int n;
scanf("%d", &n);
int * buf = (int *)malloc(100);这种处理方法虽然能节省内存空间;但是,由于需要调用malloc(),因此额外增加了程序运行时间,并且需要及时释放内存以免内存泄漏。
为了解决这个问题,C99标准引入了变长数组(Variable Length Array)。使用这种方法能更加简单有效地解决上述问题。
所谓的变长数组,指的是允许你在定义数组时,使用一个运行时变量作为数组长度。
也就是说,变长数组的定义方式非常简单:只需让数组长度使用一个变量即可。
void func(int n)
{
int buf[n];
for (int i = 0; i < n; i++) {
buf[i] = i * 2;
}
}这就使得数组的长度可以在运行时根据实际需要来确定,而不是编译时确定。
这样一来,这段代码就非常灵活了,可以充分地利用存储空间,实现“用多少分配多少”。
你可能会想,既然根据需要“动态分配”,那么这个数组的存储空间是不是像malloc()那样,从堆中动态分配?
实际上,与给定了固定长度的数组相比,只要未指定该数组为静态;那么,该变长数组是在栈上动态分配空间的。
也就是说,它的生命周期与所在函数一致,一旦函数返回,数组的空间就会自动释放。
我们可以举个ARM Cortex-M3平台上的例子来观察这一点。
假设我们有以下代码:
void test(int n)
{
int buf[n];
for (int i = 0; i < n; i++) {
buf[i] = i;
}
}对上述代码编译后,在该函数的反汇编中我们会看到以下指令:

可以看到,这段汇编代码并没有任何函数调用的操作,有的也仅仅是涉及到栈顶指针寄存器的sp的相关访问。如果仔细观察其代码;可以看到,对buf的元素的访问,实际上对当前栈空间某个存储位置的访问,
这意味着:对于变长数组而言,其占用的空间是根据传入的n,在栈上动态分配的。
这样一来,当函数返回时,这个数组的空间就会自然被释放掉。这种机制让变长数组既灵活又高效,不需要调用 malloc(),也不会造成堆碎片。
虽然变长数组很好用,但是我们在实际使用时,也有一些需要注意的地方。比如:
sizeof()求长度
因为数组长度在运行时决定,而sizeof(buf)主要在编译时确定元素的大小。所以,我们不能将其用于求动态数组的大小。变长数组为C语言带来了介于“静态数组”和“动态堆分配”之间的灵活方式。通过合理地使用变长数组,可以让你的代码既高效又简洁。
💡 作者介绍 李述铜,嵌入式系统与底层架构领域讲师,专注于操作系统、CPU 架构、RTOS 内核与系统软件实现原理的教学与研究。 出版作品《从0手写x86计算机操作系统》,主讲课程包括:《从0手写嵌入式操作系统》《从0手写TCP/IP协议栈》《从0手写FAT32文件系统》等。 课程以底层原理为核心、以可操作性为导向,帮助工程师系统理解软件与硬件之间的联系,从“能用”迈向“能造”。 欢迎关注我,或访问 👉 http://lishutong1024.cn 获取更多内容。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。