废话不多说,先上一段代码
- int main()
- {
- int n = 10;
- int arr[n];
- return 0;
- }
很简单吧,写程序写得多了的人,一眼就能看出来,这么简单的几行语句,哪里出错了。确实这几行代码放在VS2008里面绝对会报错误:error C2057: expected constant expression. 提示是第4行的错误,于是把上面的程序改成如下格式,
- int main()
- {
- int arr[10];
- return 0;
- }
程序就能在vs2008中编译通过了,这一切看来似乎理所当然,顺理成章的。
但是俺突发奇想,遂拿到g++(version 4.4.3)中编译了一下,上面的代码是可以通过编译的,另外对该数组执行了几个赋值语句,在运行期也没有报任何错误。
这下我就囧了,感觉g++这个编译器要高明很多,居然能在编译期回避这个问题。但是在我的印象中,在函数内部定义声明的变量,其内存是在函数的堆栈上开辟的,而这个堆栈的大小跟系统有关。如果在函数中任意申明一个很大的内存空间,这是比较危险的,可能会导致一些溢出问题。但是g++在这里竟然支持这种语法,就着实令人费解了,难道这是个漏洞么?
不学体系结构和编译原理很久了,不知道哪位大牛能给个解答。
原创文章,版权所有。转载请注明:转载自Vimer的程序世界 [ http://www.vimer.cn ]
本文链接地址: http://www.vimer.cn/?p=1303
我把代码改了一下:
int main(int argc, const char *argv[])
{
int n = 10;
int arr[n];
printf(“%d”,sizeof(arr));
return 0;
}
打印的结果是40,貌似还真动态分配了这么多空间。
我g++的版本是3.4.5,的确有点奇怪,一会用valgrind试一下是否会有访问越界内存的问题。
[回复]
Dante 回复:
五月 23rd, 2010 at 5:43 下午
再次改了一下程序:
int main(int argc, const char *argv[])
{
int n = 10;
int arr[n];
arr[0] = 0;
printf(“%d,%d”,sizeof(arr),arr[0]);
return 0;
}
然后用valgrind扫描,结果没有报错:
==18902== Memcheck, a memory error detector
==18902== Copyright (C) 2002-2009, and GNU GPL’d, by Julian Seward et al.
==18902== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==18902== Command: ./test
==18902== Parent PID: 17099
==18902==
==18902==
==18902== HEAP SUMMARY:
==18902== in use at exit: 0 bytes in 0 blocks
==18902== total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==18902==
==18902== All heap blocks were freed — no leaks are possible
==18902==
==18902== For counts of detected and suppressed errors, rerun with: -v
==18902== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 3 from 3)
[回复]
lr 回复:
五月 23rd, 2010 at 5:45 下午
囧,其实我就是在想,这个问题可不可以利用一下,干干坏事……
嗯,我很邪恶~
[回复]
这个就是在栈上动态分配一块内存,与gcc提供的alloca的作用差不多,本质上就是移动 esp 指针。
[回复]
lr 回复:
五月 23rd, 2010 at 5:42 下午
我说的意思,就是这个栈,函数的堆栈空间是有限的,如果在这里申请一个巨大的内存,耗尽了函数的堆栈,那不是一系列的问题就来了么?
[回复]
lr 回复:
五月 23rd, 2010 at 5:42 下午
实现这个机制肯定是容易的,我就是在想安全问题
[回复]
erlv 回复:
五月 24th, 2010 at 9:15 上午
这种动态分配内存的形式,应该是在对上分配的吧。
安全问题的话,G++应该有保证安全,估计这种变长数组和vector类型差不多。“These arrays are declared like any other automatic arrays, but with a length that is not a constant expression. ”
所以估计用它做工具,没戏:)
[回复]
同上,(我记得)这应该是一个新特性,也就是动态分配数组空间,C99里也有这个特性.至于VS为什么报错而G++不报错,那应该是应为G++对标准的支持一向要比VS好得多…
[回复]
int n = 10;
scanf(“%d”, &n);
int a[n];
printf(“%d\n”, sizeof(a));
对于这些代码,gcc产生了大量的汇编指令用来动态地在栈上分配空间。
我并不觉得这个特性有什么危险的啊!栈溢出的问题在静态数组上也是存在的啊!
况且这个特性也正反应了数组的本意,即同类型的很多“变量”,对,很多,却不知多少。这样一来
int n = 2;
int a[n];
就和
int a1, a2;
完全一样了。
[回复]
用下面选项编译
g++ -ansi -pedantic main.cc
就会报错
main.cc:4: 错误:ISO C++ 不允许变长数组 ‘arr’
变长数组时gnu c允许的,不是标准C的形式,
可以参考
http://gcc.gnu.org/onlinedocs/gcc/Variable-Length.html#Variable-Length
[回复]
雨碎江南 回复:
五月 28th, 2010 at 12:48 下午
变长数组是c99的特性啊…
[回复]
C99很牛B http://en.wikipedia.org/wiki/C99#Design
[回复]
这个是c99的标准,和c++有什么关系?c99好像只限制c了吧?这个是g++自己扩展的,非标准吧.c++0x里没见到有这个的支持…但是c和c++的编译器既然都差不多…这个,我也就闹不轻了…
[回复]
c专家编程里面貌似提过,c不允许这样使用,但是c++可以,g++当然也支持了
[回复]
MadPer 回复:
五月 23rd, 2010 at 11:39 下午
c99都支持了,c当然也可以~~但是c++好像没有官方支持这个特性.
[回复]
这不是C99支持了么……
[回复]
这是C99的内容..
[回复]
Terrence 回复:
五月 24th, 2010 at 9:23 上午
同意,C99变长数组
[回复]
C++标准和C标准貌似在C99分道扬镳了
[回复]
Fangzhen 回复:
五月 15th, 2012 at 5:27 下午
C++第一个标准是C++98,2003年对其进行过更新,称为C++03.这个标准(C++98/03)制定的时候是考虑要将C的一个标准作为子集,当时C89已经很成熟,C99还没有完全制定完,所以就选择C89作为C++中C子集标准。当然C89和C++中的C还是有些差别的。
[回复]
另外听说VS不会支持C99,不知道为啥,也没看出来官方的声明,只是道途听说
[回复]
int n=5;
int a[n];
int b[n]={};//这种情况会报错,使用变长数组时不能初始化。
int c[5]={};
[回复]
Dante 回复:
五月 24th, 2010 at 11:15 下午
试了一下,确实会报错毕竟不是运行时检查,所以编译的时候就直接报错了
[回复]
这是C99的一个新特性,可变长数组(variable length array),这个是gcc的不是g++
[回复]
c99支持变长数组,
int n=10;
{
int data[10];
}
只要多一个花括号就都通用了。
[回复]
我觉得只是一个编译优化…..
[回复]
标准的问题……
[回复]
这个叫可变数组.是GNU C的扩展…
g++ 默认用 GNU C的标准来编译
只要在 g++ 后面加个 “-ansi”参数第一个就编译不过了
===========================
你还可以试试 函数嵌套 g++一样编译的过:
int main()
{
int a()
{
return 0;
}
a();
return 0;
}
[回复]
Dante 回复:
七月 27th, 2010 at 10:50 下午
好奇怪。。。我用g++编译失败。。
x.cpp|9| error: a function-definition is not allowed here before ‘{‘ token
x.cpp|13| error: `a’ was not declared in this scope
[回复]
EzOne 回复:
八月 2nd, 2010 at 8:44 下午
…我搞错了…..
这个要GCC编译…
[回复]