gcc下处理达夫设备(Duff's device)的简单分析
int main()如果你不是码农,我觉得这篇文章就不用看了……
{
int x = 0;
int a=10;
int n=a/4;
switch(a%4)
{
case 0:
while(n--)
{
x++;
case 1:
x++;
case 2:
x++;
case 3:
x++;
};
}
return 0;
}
上面这个东西叫做Duff's device,达夫设备,看上去很吓人吧?
看上去这个编译没法通过,实际上可以。下面我们就来看看这货是怎么编译通过的,其实也不复杂。
首先得输出一下语法树或者中间文件。
用gcc有一个好,可以用gimple输出一个c like AST,官方有文档:
https://gcc.gnu.org/onlinedocs/gccint/GIMPLE.html
如果你懒得看,用gcc输出语法树的方法在下面:
-fdump-tree-gimple 可以输出ast到一个文件我们打开dump文件
用法:gcc -fdump-tree-gimple main.c
main ()看起来不太容易懂,那么我们把switch语句删掉:
{
int D.2176;
_Bool D.2177;
int D.2179;
int x;
int a;
int n;
x = 0;
a = 10;
n = a / 4;
D.2176 = a % 4;
switch (D.2176) <default: <D.2178>, case 0: <D.2168>, case 1: <D.2169>, case 2: <D.2170>, case 3: <D.2171>>
<D.2168>:
goto <D.2173>;
<D.2172>:
x = x + 1;
<D.2169>:
x = x + 1;
<D.2170>:
x = x + 1;
<D.2171>:
x = x + 1;
<D.2173>:
D.2177 = n != 0;
n = n - 1;
if (D.2177 != 0) goto <D.2172>; else goto <D.2174>;
<D.2174>:
<D.2178>:
D.2179 = 0;
return D.2179;
}
main ()对比一下,其实就很简单了,就容易看出来switch语句是怎么编译的了:
{
_Bool D.2172;
int D.2173;
int x;
int a;
int n;
x = 0;
a = 10;
n = a / 4;
goto <D.2169>;
<D.2168>:
x = x + 1;
x = x + 1;
x = x + 1;
x = x + 1;
<D.2169>:
D.2172 = n != 0;
n = n - 1;
if (D.2172 != 0) goto <D.2168>; else goto <D.2170>;
<D.2170>:
D.2173 = 0;
return D.2173;
}
int main()也就是说,这个表达是完全可以编译的。
{
int x = 0;
int a=10;
int n=a/4;
if a%4==0 goto case0;
if a%4==1 goto case1;
if a%4==2 goto case2;
if a%4==3 goto case3;
//case相当于数个goto的flag
{
case 0:
while(n--)
{
x++;
case 1:
x++;
case 2:
x++;
case 3:
x++;
};//经过测试,这个分号不重要,有没有都不影响编译
}
return 0;
}
{ int a = 0; }
int a = 0;
以上两个表达,区别是多少一个括号,这在编译中不影响表达
while(条件)
{
语句块;
}
这个是这样编译的:
goto flag2
flag1
{
语句块;
}
flag2
{
判断语句;
成立跳转flag1
}
for和dowhile语句都是类似的方式。
3 个评论
小白提问:达夫设备是干嘛的呀?为什么看上去无法编译?

Eidosper(作者) 评论 Joey
编译过程中的手工展开循环,试过可以编译的。神奇的嵌套是因为switch while语句实际上不是一个语句。
这个技巧可以减少判断的次数,对于一个n次的循环,需要n次判断和n次执行,但是用这个技巧可以让判断次数除以k,但代码会对应长k倍。现代编译器通常自带循环展开,明天我打算试试优化参数看看对应汇编代码。
换言之,这东西大概在古代有优化作用。
这个技巧可以减少判断的次数,对于一个n次的循环,需要n次判断和n次执行,但是用这个技巧可以让判断次数除以k,但代码会对应长k倍。现代编译器通常自带循环展开,明天我打算试试优化参数看看对应汇编代码。
换言之,这东西大概在古代有优化作用。
其实就是跳转表。。。