天秤座的唐风

总会有一个人需要你的分享~!- 唐风 -

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  13 随笔 :: 0 文章 :: 69 评论 :: 0 Trackbacks

    先看下面这一段程序:

 1#include "stdafx.h"
 2
 3#include <boost/bind.hpp>
 4#include <vector>
 5#include <string>
 6#include <iostream>
 7#include <list>
 8#include <algorithm>
 9
10using namespace std;
11using namespace boost;
12
13struct Test
14{
15    Test& fun1(int &i) {
16        cout<<"Function 1 : i = "<<i<<endl;
17        return *this;
18    }

19    Test& fun2(int &i) {
20        cout<<"Function 2 : i = "<<i<<endl;
21        return *this;
22    }

23    Test& fun3(int i) {
24        cout<<"Function 3 : i = "<<i<<endl;
25        
26        return *this;
27    }

28
29    void fun4(int i, Test& t) {
30        cout<<"Function 4 : i = "<<i<<endl;
31    }

32}
;
33
34int _tmain(int argc, _TCHAR* argv[])
35{
36    
37    Test a;
38    int i = 0;
39
40    cout<<i<<" "<<i++<<endl;
41    i = 0;
42    printf("%d, %d\n", i, i++);
43
44    i = 0;
45    a.fun3(++i).fun3(i++);
46    i = 0;
47    a.fun1(++i).fun3(i++);
48
49    i = 0;
50    a.fun4(i, a.fun3(i++));
51
52    return 0;
53}


    这段程序的输出结果,多多少少让人感觉有点意外。
    我们先看下面这句:

cout<<i<<" "<<i++<<endl;


    按惯常的思维来说,我们认为的结果是第一次输出 0 ,第二次输出也是 0 ,之后,变量 i 的值变成 1 。
    但实际上,第一次输出了 1 ,第二次输出的是 0 。
    为什么呢?原来在一个语句中,如果存在多个函数调用,那么参数值会从右到左处理一遍,之后再从左到右调用每个函数。从右到左处理参数是为了满足 C/C++ 的变参数函数的要求,而从左到右的调用函数则是与书写习惯相符合的。
    那么,这个语句中,先把 i 的值赋给第二个输出流操作符,然后进行自加,再将 i 的值(自加之后的)赋给第一个输出流操作符。结果和我们预想的“正常行为”就不太一样了。
    其实同样的,如果这里不是用输出流,而用 C 的printf ,比如:

printf("%d ,%", i , i++)


    在上面的情况下,程序的行为经过解释之后,我们还是能够理解的。
    第X、Y行的代码行为,就难以解释了。(我怀疑这是微软编译器的bug,呵呵)
    第 45 行,fun3 得到的是 i 自加前的值,而第 47 行,fun3 得到的则是 i 自加后的值,两者的区别只是因为前一个函数中,i 是值传递还是以引用传递。这一点,只要看下对应的汇编代码就能进行验证。

总结下:
    自加与自减表达式用在函数调用中,是非常容易产生副作用的。它所带来的便利性比较小,但如果产生了隐蔽的 bug,则很难进行查找和处理,可能花费很多时间和精力。所以,至少在团队合作进行开发时,看情况适当地禁止这种可能产生副作用的用法,是值得的。

PS:
    以上程序在VC2003和VC2008中验证。

posted on 2009-07-05 12:40 唐风 阅读(426) 评论(0)  编辑 收藏 引用 所属分类: 语言技术

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理