轉(zhuǎn)載自神的blog
http://blog.csdn.net/vbvan/archive/2007/10/30/1856481.aspx
搞掛你的C++編譯器 Play with the compiler是一件很有趣的事情,編譯死循環(huán)的程序便是其中之一。讓我們和編譯器一起做游戲吧~
1、Preprocess
a、Self Include(GCC only)
一般的編譯器都有include嵌套層數(shù)的限制,所以你需要在適當(dāng)?shù)臅r(shí)候停止嵌套。利用GCC提供的__INCLUDE_LEVEL__可以很輕松的實(shí)現(xiàn)這一點(diǎn)。時(shí)間復(fù)雜度是n
a,n是每層的Self Include次數(shù),a是嵌套層數(shù)。
在其它編譯器中可以寫(xiě)出類(lèi)似的代碼,只是沒(méi)這么簡(jiǎn)潔
#if __INCLUDE_LEVEL__<199
#include __FILE__
#include __FILE__
#endif
b、Macro Expansion Explosion
顧名思義,就是讓Preprocess之后的代碼量達(dá)到O(2
n),比如下例:
#define F1(x) x,x
#define F2(x) F1(x),F1(x)
#define F3(x) F2(x),F2(x)
#define F4(x) F3(x),F3(x)
#define F5(x) F4(x),F4(x)
#define F6(x) F5(x),F5(x)
#define F7(x) F6(x),F6(x)
#define F8(x) F7(x),F7(x)
#define F9(x) F8(x),F8(x)
#define G1(x) F9(x),F9(x)
#define G2(x) G1(x),G1(x)
#define G3(x) G2(x),G2(x)
#define G4(x) G3(x),G3(x)
#define G5(x) G4(x),G4(x)
#define G6(x) G5(x),G5(x)
#define G7(x) G6(x),G6(x)
#define G8(x) G7(x),G7(x)
#define G9(x) G8(x),G8(x)
int main()
{
G9(1);
}
當(dāng)然,不同的編譯器對(duì)預(yù)處理結(jié)果溢出的處理也不盡相同,一般上面的代碼不會(huì)達(dá)到預(yù)期的目的。GCC會(huì)直接出錯(cuò),而VC會(huì)出ICE(Internal Compiler Error)
2、Template
a、嵌套
類(lèi)似的,模版也有嵌套層數(shù)限制,但是也很容易繞過(guò)。
GCC的某些版本就會(huì)被下面的代碼搞掛(VC不會(huì)):
#include <cstddef>
template <class T>
struct Test {
static const size_t Value=Test<Test<T> >::Value;
};
不過(guò)利用VC的某個(gè)bug(或者說(shuō)特性),可以很容易的寫(xiě)出O(n
a)編譯時(shí)間的模版:
#include <cstddef>
#define INNER(A3,N3,A2,N2) \
template<size_t N3>\
struct A3\
{\
enum {N=A3<N3-1>::N+1};\
};\
template<>\
struct A3<0>\
{\
enum {N=A2<N2-1>::N};\
};
#define OUTER(A2,N2,A1,N1,A3,CONTENT) \
template<size_t N2>\
struct A2\
{\
CONTENT\
\
enum {N=A3<N2>::N};\
};\
template<>\
struct A2<0>\
{\
enum {N=A1<N1-1>::N};\
};
#define LEVEL2(a,b,c) INNER(A##b,N##b,A##a,N##a)
#define LEVEL3(a,b,c) OUTER(A##b,N##b,A##a,N##a,A##c,LEVEL2(a##1,b##1,c##1))
#define LEVEL4(a,b,c) OUTER(A##b,N##b,A##a,N##a,A##c,LEVEL3(a##1,b##1,c##1))
#define LEVEL5(a,b,c) OUTER(A##b,N##b,A##a,N##a,A##c,LEVEL4(a##1,b##1,c##1))
template<size_t N1>
struct A1
{
LEVEL5(1,11,111)
enum {N=A11<N1>::N};
};
template<>
struct A1<0>
{
enum {N=0};
};
這里比較有趣的一點(diǎn)是,標(biāo)準(zhǔn)并不允許這樣在模版類(lèi)里的特化。不知道這個(gè)算VC的bug呢還是擴(kuò)展呢
A member or a member template may be nested within many enclosing class templates. In an explicit specialization for such a member, the member declaration shall be preceded by a template<> for each enclosing class template that is explicitly specialized基于類(lèi)似的思想,GCC&VC通用的版本也不難寫(xiě)出。
b、OLE
雖然通常模版的編譯時(shí)間都是O(n)的,不過(guò)很多編譯器的錯(cuò)誤信息輸出卻是O(n
2)的,利用這一點(diǎn)+很長(zhǎng)的類(lèi)名,很容易造成錯(cuò)誤信息的Output Limit Exceed。比如:
#define ClassName A
template <int N>
class ClassName
{
enum {Value=ClassName<N-1>::Value};
};
int main()
{
int n=ClassName<0>::Value;
}
如果我把ClassName改成某個(gè)很長(zhǎng)的名稱(chēng)(現(xiàn)代的編譯器都支持很長(zhǎng)的變量名),那么錯(cuò)誤輸出就很容易OLE
PS:上面的代碼在VC8里會(huì)直接出ICE,不過(guò)這是VC8的bug。VC2008沒(méi)有這樣的問(wèn)題
posted @
2007-11-02 18:08 shifan3 閱讀(1025) |
評(píng)論 (0) |
編輯 收藏
轉(zhuǎn)載自神的blog
http://blog.csdn.net/vbvan/archive/2007/10/30/1857134.aspxFlexible C++
C++是一門(mén)非常靈活的語(yǔ)言,只要充分發(fā)揮你的想象, 再普通的東西都能玩出新花樣
1、1~1000求和
循環(huán)?遞歸?再簡(jiǎn)單不過(guò)的題目了。但是如果不允許你用判斷語(yǔ)句呢?
如果你熟悉switch的內(nèi)部實(shí)現(xiàn),那么你很容易想到使用函數(shù)指針數(shù)組。
#include <cstdio>
typedef int (*fun)(int);
int f1(int i) {return 0;}
int f2(int i) {fun f[2]={f1,f2}; return i+f[!!i](i-1);}
int main()
{
printf("%d\n",f2(1000));
}
2、輸出1,2,...,100,99,...,2,1
如果同樣不讓你用判斷語(yǔ)句呢?你仍然可以使用函數(shù)指針數(shù)組:
#include <cstdio>
typedef void (*fun)(int i,int n);
void f1(int i,int n);
void f2(int i,int n);
void f3(int i,int n);
void f1(int i,int n)
{
fun f[2]={f1,f2};
printf("%d\n",i);
f[i+1==n](i+1,n);
}
void f2(int i,int n)
{
fun f[2]={f2,f3};
printf("%d\n",i);
f[i==1](i-1,n);
}
void f3(int i,int n) {}
int main()
{
f1(1,100);
}
不過(guò)我們有更簡(jiǎn)潔的方法。
短路算法和逗號(hào)表達(dá)式粉墨登場(chǎng)了,一行搞定~
#include <cstdio>
void f(int i,int n)
{
printf("%d\n",i),(i<n)&&(f(i+1,n),printf("%d\n",i));
}
int main()
{
f(1,100);
}
posted @
2007-11-02 18:05 shifan3 閱讀(1364) |
評(píng)論 (3) |
編輯 收藏