Posted on 2010-10-08 00:06
李熙建 阅读(396)
评论(0) 编辑 收藏 引用 所属分类:
C++
某公司的笔试题本意是想考察学生对于指针问题的理解和应用,在做测试的时候发现使用连<<输出符号一些有趣的问题,在参数是表达式的情况下,分析一下编译器是如何处理连<<问题的
#include <iostream>
using namespace std;
int main()
{
char* a[] = {"abc","def","ghi","jkl"};
char **p = a;
cout<<*p++<<",";
cout<<++*p<<",";
cout<<p[1]<<endl;
return 0;
}
输出结果为:abc,ef,ghi 这个没问题,要注意一点的是++运算符优先级高于 “*”解引用运算符。
下面我们把这三个cout写成一条语句,先分析一下结果会是怎么样呢?
#include <iostream>
using namespace std;
int main()
{
char* a[] = {"abc","def","ghi","jkl"};
char **p = a;
cout<<*p++<<","
<<++*p<<","
<<p[1]<<endl;;
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>
using namespace std;
int main()
{
char* a[] = {"abc","def","ghi","jkl"};
char **p = a;
cout<<++*p<<","
<<*p++<<","
<<p[1]<<endl;;
return 0;
}
//程序运行结果:ef,abc,ghi