chen3feng / article

本人的文章和笔记,充当懒人 Blog 来用。
9 stars 1 forks source link

可变长度数组的风险与解决方式 #11

Open chen3feng opened 3 years ago

chen3feng commented 3 years ago

可变长度数组的风险与解决方式

什么是 VLA

可变长度数组(Variable Length Array,简称 VLA)是 C99 开始支持的一种语法:

void f(int size) {
  char tmp[size];
  ...
}

和普通数组最大的区别是,数组的大小是由一个运行期间才知道值的变量决定的。

Gcc很早就以非标准扩展方式支持 VLA(包括在C++中),ANSI C90 及标准 C++ 都不支持可变长度数组。

VLA 的问题

VLA 看上去很方便,也很符合直觉,所以不少对 C/C++ 不够熟悉的程序员在代码中不知不觉就用上了。但是其实 VLA 带来的问题更多:

因此,C++代码规范禁用了 VLA,Linux内核也禁用了VLA

和 VLA 类似的是 alloca 函数,也在禁用之列。

VLA 的替代方案

如果已知数组长度不会超过某个不太大的值,可以用固定长度的数组代替:

void f(int size) {
  if (size > MAX_SIZE) return;
  char tmp[MAX_SIZE];
  ...
}

否则可以用动态分配代替(C++中则应该用 string, vector 等封装好的容器避免内存泄漏)。 如果这段代码的性能非常重要,这两种方式还可以结合起来使用:

void f(int size) {
  if (size <= MAX_SIZE) {
    char tmp[MAX_SIZE];
    ...
  } else {
    std::vector<char> tmp(MAX_SIZE);
    ...
  }
}

编译时禁用 VLA

GCC 默认是允许 VLA 的,通过设置 -Werror=Vla 参数,可以在编译时禁用 VLA。 对于一些不想改代码的第三方库,如果 VLA 出现在头文件中,可以通过GCC 的 pragma diagnostic局部允许。