Posted on 2010-10-08 00:06 
李熙建 阅读(426) 
评论(0)  编辑 收藏 引用  所属分类: 
C++ 
			 
			
		 
		某公司的笔试题本意是想考察学生对于指针问题的理解和应用,在做测试的时候发现使用连<<输出符号一些有趣的问题,在参数是表达式的情况下,分析一下编译器是如何处理连<<问题的
 #include <iostream>
#include <iostream>
 using namespace std;
using namespace std;
 int main()
int main()


 {
{

 char* a[] =
    char* a[] =  {"abc","def","ghi","jkl"};
{"abc","def","ghi","jkl"};
 char **p = a;
    char **p = a;
 cout<<*p++<<",";
    cout<<*p++<<",";
 cout<<++*p<<",";
    cout<<++*p<<",";
 cout<<p[1]<<endl;
    cout<<p[1]<<endl;
 return 0;
    return 0;
 }
}这个没问题,要注意一点的是++运算符优先级高于 “*”解引用运算符。
下面我们把这三个cout写成一条语句,先分析一下结果会是怎么样呢?
 #include <iostream>
#include <iostream>
 using namespace std;
using namespace std;
 int main()
int main()


 {
{

 char* a[] =
    char* a[] =  {"abc","def","ghi","jkl"};
{"abc","def","ghi","jkl"};
 char **p = a;
    char **p = a;
 cout<<*p++<<","
    cout<<*p++<<","
 <<++*p<<","
        <<++*p<<","
 <<p[1]<<endl;;
        <<p[1]<<endl;;
 return 0;
    return 0;
 }
}
还会是上面的输出结果吗?
输出结果为:bc,def,ghi分析:
通过查看汇编代码我们发现,编译器先首先检查,如果<<参数为表达式,先会计算每个参数的值,并且计算的顺序是从右到左的
1.由于p[1]已经可以直接读取了,不需要计算,
 首先计算 ++*p ,*p指向abc中a的地址,经过自加操作后指向b的地址
2.其次,计算*p++ ,编译器会把*p的值保存到栈的一个位置,当前*p就是上一步计算得到的值,然后将p++,这个时候p就指向了 串"def"的首地址
3.参数入栈,p[1]入栈,p[1]指向串"ghi"的首地址,所以p[1]的值为"ghi"
4.++*p的值入栈,当前p指向串"def"的首地址 所以++*p的值为"def"
5.*p++的值入栈,是当时保存的p++之前的*p的值 "bc" 所以*p++的值为"bc"
6.从左向右call三次<<输出重载操作符函数,每次调用形式为basic_ostream&<<(basic_ostream& cout,char*)
建议:从上面的分析可以看出,在使用cout输出的时候,最好不要使用连<<,如果要使用的话,尽量保证每个输出对象是单个的值,而不是表达式,表达式可能输出的结果和我们的期望相差很大。
比如,我们把上面的两个参数交换一下,感兴趣的朋友可以试着分析一下:
 #include <iostream>
#include <iostream>
 using namespace std;
using namespace std;
 int main()
int main()


 {
{

 char* a[] =
    char* a[] =  {"abc","def","ghi","jkl"};
{"abc","def","ghi","jkl"};
 char **p = a;
    char **p = a;
 cout<<++*p<<","
    cout<<++*p<<","
 <<*p++<<","
        <<*p++<<","
 <<p[1]<<endl;;
        <<p[1]<<endl;;
 return 0;
    return 0;
 }
}
 //程序运行结果:ef,abc,ghi
//程序运行结果:ef,abc,ghi