Tchaikov’s Journal

September 12, 2006

C++表达式中的副作用

Filed under: C++

昨天,有同学给我看这样的程序:

int fun(int n)
{
    if(++n==5)
	return n++;
    else {
	return n*fun(n++);
    }
}

问,

fun(1)
得多少?咋一看,这不是求 5! 么?再看,
++n==5
已经让 n+=1 了,那就应该是这样的:

f(1)
 2  *  f(2)
        3  *  f(3)
               4  *  f(4)
                       5

答案应该是 120。作为一个悲观的 code warrior,我没有就此停止,我习惯性地把段代码贴进 Emacs,编译了一把,运行结果竟然是……300。我瘫坐在椅子里,听着外面淅淅沥沥的雨声。不是说“*”号是从左到右么?怎么会这样。再看了一眼 K&R 的 TCPL,第53页里表格说的是 associativity,不是 evaluate order。而且就在这一页,作者提到了

C, like most languages, does not specify the order in which the operands of an operator are evaluated.

函数参数的情形也一样。

C++标准 ISO/IEC 14882-2003 chap5.4 也提到

Except where noted, the order of evaluation of operands of individual operators and subexpressions of individual expressions, and the order in which side effects take place, is unspecified.

Unspecified behaviour 和 undefined behaviour 真是 C/C++ 程序员的噩梦。故事如果发生在不使用副作用的函数语言(比如 Scheme)那里,应该就没有这种问题了。

2 Comments »

The URI to TrackBack this entry is: http://tchaikov.blogsome.com/2006/09/12/p59/trackback/

  1. 看了这片blog,我个人对此的解释可能和你不同。
    前边一样:
    f(1)
    2 * f(2)
    3 * f(3)
    4 * f(4)
    5
    但是返回的部分还需要对n++,也就是(4++)*5 = 25,(3++)*25 = 100,(2++)*100 = 300。
    我跟踪了一下,大概应该是这样,也可能是我理解有误,如果有什么其他见解我很有兴趣知道。

    Comment by allen — March 6, 2007 @ 7:12 am

  2. hi allen,

    谢谢你的提醒。

    但是你可能误会我的意思了。我这篇短文的意思主要是为了澄清,求值顺序和结合顺序是两码事。而我们常常会把两个概念混淆,认为求值顺序就是结合顺序。不过文中只是点到为止,就没有把问题说清楚了。

    这段代码我也调试过,结论和你的结果是一致的。8-)

    Comment by Administrator — March 6, 2007 @ 11:51 am

RSS feed for comments on this post.

Leave a comment

Line and paragraph breaks automatic, e-mail address never displayed, HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>


Get free blog up and running in minutes with Blogsome
Theme designed by Jay of onefinejay.com