事情的起因
事情是这样子滴,有一次我在代码评审的时候,发现有同事想使用运行时才能够获取到的值,去改变一个静态数组的元素个数,我当时就很诧异,因为我心里知道这样是不可行的,静态数组的元素个数在编译时就需要是固定不变的,一般只能是常量或者宏定义,否则编译就不能通过。
但是当时我提出来以后,把原因说了,包括写出这个代码的人和另外一位同事都没理解,弄得我有点怀疑自己了,难道是我搞错了?
我左思右想,最后我写了下面的代码来证实一下:
#include <iostream>
using namespace std;
int get()
{
int size = 0;
cout << "please input a num:";
cin >> size;
return size;
}
int main()
{
int size = 1000;
size = get();
int arr[size] = {0};
cout << "arr's size is " << sizeof(arr)/sizeof(arr[0]) << endl;
return 0;
}
我打心底认为,这段程序肯定是编译不通过的,但是结果打脸了。编译后执行显示如下:
please input a num:10000
arr's size is 10000
不仅编译通过了,而且数组大小还在运行时修改了,可是我明明定义的是一个静态数组呀,而且就算我这里不给size赋初始值1000,结果也还是一样的。
探索的过程
简直是见了鬼了,我把代码看了又看,认为是我代码写错了,但是这么简单的一段代码,我不可能写错呀。后来我突然想到,会不会是有了新的语法?
因为我现在的gcc编译器,大家都知道是7.1.0的版本,基本上连c++17都能支持了,我就试了一下之前保留的gcc4.1.2的版本,结果报错啦,如下:
test.cpp: In function ‘int main()’:
test.cpp:15: 错误:可变大小的对象 ‘arr’ 不能被初始化
所以很显然,我的记忆没有错误,之前静态数组的元素个数它就必须是个不可变的,否则编译就会出错。
然后我又看了下生产上用的编译器,是gcc4.8.5的版本,它也是支持c++11的,难道这个新的特性是c++11支持的吗?然后我去cppreference把c++11的新特性从头到尾翻了一遍,并没有对这个修改有说明,并且网上搜索,所有的文章都在说c和c++想使用变长数组,就必须要使用动态数组,我一度陷入了僵局,但是我并没有死心,继续探索。
后来我忽然想到,假如不是c++的新特性,那是不是c语言的新特性呢,想到这里,我把代码做了如下修改:
#include <stdio.h>
int get()
{
int size = 0;
printf("please input a num:");
scanf("%d", &size);
return size;
}
int main()
{
int size = 1000;
size = get();
int arr[size] = {0};
printf("arr's size is %d\n", sizeof(arr)/sizeof(arr[0]));
return 0;
}
然后直接使用gcc命令编译,而没有使用g++,结果跟上面那段代码是一模一样的,到这里我大致上就明白了,这就是c语言里面的新特性。
欣喜的找到了结果
最后我在cppreference这个链接里面看到了对于c99的说明:
- 新特性: Bool 、 long long 、 stdint.h 、 inttypes.h 、 restrict 、复合字面量、变长度数组、伸缩数组成员、指派初始化器、 fenv.h 、变参数宏、复数、 func 、十六进制浮点格式( %a )、 lconv 的货币格式化、 isblank 、窄与宽字符串字面量的连接、枚举的尾逗号、类函数宏的空参数、 STDC* pragma 、 va_copy 、 tmpnam 的空返回、 setvbuf 中的空指针、 printf 的 hh 与 ll 长度指定符、 snprintf 、 _Exit 、 tgmath.h 、仿 POSIX strftime 说明符
- 来自 C++ : inline 、声明与代码混合、 for 循环的 init 子句中的声明、
**//**
注释、源代码中的通用字符名- 移除隐式函数声明和隐式 int
看看,是不是明确说明了新特性是变长度数组,并且是c语言99年的标准,有点灯下黑了,以后如果再看到有人说c语言和c++的静态数组都只支持固定长度,要想变长就必须要使用malloc和new,就可以唾弃一下啦。
另外有一点需要注意的是,如果我们的场景真的是需要使用固定大小的数组,那么最好使用常量和宏定义,再不然,就使用c++11里面新增加的array。