一段Old Style C代码:不带类型声明的形参

2012-09-13

想想看下面一段程序的输出是什么?注意看sqr函数的形参部分,噢,它真的是合法的,只是模样有点古怪,这就是所谓的Old Style C(K&R C)。

double sqr(x) { return x * x; }
int main()
{
	printf("sqr(3.0): %f\n", sqr(3.0));
	printf("sqr(3): %f\n", sqr(3));
	return 0;
}

在我的机器上,结果是:

sqr(3.0): 0.000000
sqr(3): 9.000000

如果没有为形参指定类型,结果是未定义的。试了几个编译器和机器,都采用将实参转为整数的方式,所以3.0变成了0。

可是,3.0转换为0的时候,发生了什么呢?让我们看看(VC生成的)汇编码:

printf("sqr(3.0): %f\n", sqr(3.0));
0040EA08   push        40080000h
0040EA0D   push        0
0040EA0F   call        @ILT+0(_sqr) (00401005)
0040EA14   fstp        qword ptr [esp]
0040EA17   push        offset string "sqr(*p++): %f\n" (00424fe0)
0040EA1C   call        printf (00401170)
0040EA21   add         esp

在这段代码的头2行,我们看到了两个连续的压栈操作,似乎是想传2个参数进去。sqr只需要一个参数,所以只取了后进栈的参数,即0,所以上述程序结果是0.

那么,这个0,还有那个40080000h是怎么来的呢?这就牵涉到double类型的数据表示方法,以及小尾端的知识了。double有64位,从左往右,先是1位符号位,再是11位阶符,最后是52位尾数,其中阶要加上1023。所以3.0的浮点表示应该是4008-0000-0000-0000H,再转换为小尾端的顺序,就是0000-0000-0000-0840H,将3.0转换为int时,分成了2个int数据,头一个是0,后一个再转为正常顺序就是40080000H。

到这里,试着将sqr的声明改为:double sqr(x, y),同样传3.0进去,则x赋为0,y赋为40080000H。

这段代码改自P.J Plaucer的著作The Standard C Library 中第0章的习题。摘抄这本书的代码真有点不放心啊,Plaucer在前言里面的版权声明好吓人……不过,刚开始看到这段代码的输出,着实吓了一跳。也许这段古董代码的最大意义,就是告诫我们,不要使用未定义的编程方式吧。

« 二分图最大匹配的贪心解法及证明  小报栏 »

comments powered by Disqus