今天考试考了一道需要递归 $10^5$层的题目。。。
然后我就发现我爆栈了
然后我就手写模拟栈递归浪费了很多时间
虽然其实评测的时候带了编译开栈命令,但是那个命令是 Windows 底下的,所以我 Ubuntu 就没辙了。
然后去网上搜手动开栈,但都是很久以前的代码,目前的 G++编译器已经不能编译了 QvQ
最后找到一段报错还算比较少的代码,改了改就能用了。
Windows10 64 位版本和 Ubuntu 16.04 LTS 64 位版本下编译测试通过。
G++版本:
g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
首先我们上一段会爆栈的代码
#include <bits/stdc++.h>
using namespace std;
void main2()
{
int arr[10000000];
puts("QvQ"), exit(0);
}
int main(int argc, char const* argv[])
{
main2();
return 0;
}
很显然不会输出”QvQ” 这三个字,而会直接爆栈 Segment Fault,因为在函数 main2() 内开了个 38MB 的数组,而 Ubuntu 下栈空间默认是 8MB。
我们再上一段扩栈后的代码
#include <bits/stdc++.h>
using namespace std;
extern void main2(void) __asm__ ("main2");
void main2()
{
int arr[10000000];
puts("QvQ"), exit(0);
}
int main(int argc, char const* argv[])
{
int size = 128 << 20; // 128 MB
char* p = new char[size] + size;
__asm__ __volatile__(
"movq %0, %%rsp\n"
"pushq $exit\n"
"jmp main2\n"
:: "r"(p));
main2();
return 0;
}
于是我们就愉♂快地发现它没有爆栈,而是输出了可爱的 “QvQ”
这是因为我们先申请了 128MB 的内存,并用指针 p 表示这段内存。
然后我们把 main2() 所申请的栈空间放在了 p 里面
实际上如果在 main2() 里调用函数,比如这样:
#include <bits/stdc++.h>
using namespace std;
extern void main2(void) __asm__ ("main2");
void boom()
{
int arr[10000000];
}
void main2()
{
boom();
puts("QvQ"), exit(0);
}
int main(int argc, char const* argv[])
{
int size = 128 << 20; // 128 MB
char* p = new char[size] + size;
__asm__ __volatile__(
"movq %0, %%rsp\n"
"pushq $exit\n"
"jmp main2\n"
:: "r"(p));
main2();
return 0;
}
是依然能输出可爱的”QvQ” 的!
因为 boom() 函数也是在 main2() 内调用的!
所以栈空间也会存到 p 内
这就意味着我们可以用这个扩栈来防止递归爆栈。。。
真是有趣 QvQ
不过好像 BZOJ 上会 CE,估计是它的编译器实在是版本太老了
别的 OJ 没试过 QvQ
另外 32 位机也没试过,要是有同学试了 32 位机的请在底下留言告诉我情况吧哈哈= ̄ω ̄=
Update
有同学反馈代码在 32 位机上运行正常
(^-^)V
13 条评论