搞挂编译器是一件很有趣的事情,编译死循环的程序便是其中之一。让我们和编译器一起做游戏吧~
1、Preprocess
a、Self Include(GCC only)
一般的编译器都有include嵌套层数的限制,所以你需要在适当的时候停止嵌套。利用GCC提供的__INCLUDE_LEVEL__可以很轻松的实现这一点。时间复杂度是na,n是每层的Self Include次数,a是嵌套层数。
在其它编译器中可以写出类似的代码,只是没这么简洁
#if __INCLUDE_LEVEL__<199
#include __FILE__
#include __FILE__
#endif
b、Macro Expansion Explosion
顾名思义,就是让Preprocess之后的代码量达到O(2n),比如下例:
#define F1(x) x,x int main() |
当然,不同的编译器对预处理结果溢出的处理也不尽相同,一般上面的代码不会达到预期的目的。GCC会直接出错,而VC会出ICE(Internal Compiler Error)
2、Template
a、嵌套
类似的,模版也有嵌套层数限制,但是也很容易绕过。
GCC的某些版本就会被下面的代码搞挂(VC不会):
#include <cstddef> template <class T> struct Test { static const size_t Value=Test<Test<T> >::Value; }; |
#include <cstddef> #define INNER(A3,N3,A2,N2) \ #define OUTER(A2,N2,A1,N1,A3,CONTENT) \ #define LEVEL2(a,b,c) INNER(A##b,N##b,A##a,N##a) template<size_t N1> int main() |