本文作者:Tianheng Ni
本文分类:编程学习笔记 浏览:1801
阅读时间:1967字, 约2-3.5分钟
前情提要:昨天srt同学给我看了一段代码,出现了一个很奇怪的问题,就是cout出现在程序main函数的最前面,却没有输出:
#include<bits/stdc++.h>
using namespace std;
const int MOD=2009;
const int N=105;
struct Matrix
{
int a[N][N];
int n,m;
Matrix(int n=0,int m=0):n(n),m(m){memset(a,0,sizeof(a));}
void init(int _n=0,int _m=0){n=_n;m=_m;memset(a,0,sizeof(a));}
Matrix operator*(Matrix b)
{
/*
省略
*/
return ans;
}
};
Matrix qpow(Matrix a,int n)
{
/*
省略
*/
}
int n,t,cnt;
int main()
{
cout << "hello world\n" << endl;
cin>>n>>t;
Matrix A,B;
/*
省略
*/
return 0;
}
经过研究与和hyq同学的讨论,我最终找到了这个问题的根源。
打开gdb,在CPU Dump中,指出了问题所在的位置:
是“__chkstk_ms()”中的问题。不过似乎这不能说明什么问题,我们就继续查找思路。
首先,我们打开任务管理器,发现过程是RAM占用不断增加,直至报Segmentation Fault,被迫中止。因此确定了问题在于内存爆了导致的段错误。
我昨晚和hyq讨论了很久是否是在循环过程中因为大量创建的临时变量未被析构而导致占用了大量内存,但是事实证明并非如此。其实就是开了1005*1005的int数组就大到足以报错了。如这段我简化过后的程序:
#include <bits/stdc++.h>
using namespace std;
int main() {
system("pause");
int x[1000][1000];
memset(x,0,sizeof(x));
return 0;
}
在电脑上会重现与昨日一样的错误。因此这个“哪里出了问题”这个问题已经被解决了。
下一个问题,为什么昨天即使把 Matrix A,B; 这个定义语句放到了cout的后面,cout也无法输出。
我通过Compiler Explorer(https://godbolt.org/,超级好用)查看了编译我写的测试程序得到的汇编代码,摘录如下:
main:
sub rsp, 4000008
mov edx, 4000000
mov esi, 0
mov rdi, rsp
call memset
mov eax, 0
add rsp, 4000008
ret
可以看到,程序的入口点处(即“main”的后一行)就出现了对rsp寄存器值减去4000008的操作,而4000000就是1000*1000*4(sizeof int),所以这些变量会占用的栈空间在程序开头即被预留,注意rsp即为栈顶指针,减去后它小于了栈基指针的值,便出现了段错误。问题至此就解释清楚了。
注意在我为了复现而编写的代码中保留了 memset(x,0,sizeof(x)) 一句,因为只有通过memset初始化了后C++才会预留这一部分空间。对于下列代码
int main() {
int x[1000][1000];
return 0;
}
编译得到的汇编是
main:
mov eax, 0
ret
并没有预留空间的操作。
关于作者Tianheng Ni
- 卑微站长23564~ 苣蒻OIer,电脑爱好者,喜欢C++编程/折腾网站
- Email: eric_ni2008@163.com
- 注册于: 2020-04-05 07:11:36