学习C++时遇到的一个小问题&&解决
一、疑惑
以上的代码运行之后输入
first 255 second 1023
为什么输出是second|255,而不是second|1023或者first|1023呢?
二、通过汇编代码查看
在VC++6.0中设置断点,按F5运行。
从上面的代码可以发现,编译器是按从右到左进栈的。这应该就是_cdecl调用方式的特点。
00401874:调用了a.get_score(a),在命令提示符界面上输入小于10个字符串+int型数据。
然后00401879~0040187D:是进栈的操作,用于最后的输出’|’和socre的值
进制顺序为:a.socre的值-->’|’的地址
00401889:第二次调用a.get_score(a),在命令提示符上输入小于10个字符串+int型数据。
0040188E:函数返回值EAX是a.name的地址,进栈,用于输出name的字符串
00401894:输出的是第二次输入的name
0040189D:输出的是’|’
004018A7:输出的是第一次输入的socre
004018AE:输出的是endl
输出为:second|255
总结:原来编译器这样子做的,关键的地方就是编译器在第一次调用a.get_score(a)之后就对输出进行了处理, socre是直接采用int值进栈的,所以导致了在第二次调用a.get_score(a)之后,输出的socre是第一次输入的,因为之前进栈的是立即数,不是地址。
三、如果socre的类型不是int呢?
① 成员变量修改为:
char name[10];
char socre[10];
00401379:用于输出socre,此时进栈的不是立即数,而是地址了
②成员变量修改为:
int name;
int socre;
输入:12 34 56 78
输出:56|34
00401890:输出name,进栈的是立即数
所以,字符串输出用到地址,数值输出用到数值本身。
四、如果编译器不是VC++6.0,而是采用g++在命令行里编译
输入:first 255 second 1023
输出:second|1023
显然跟用cl.exe编译不同,为什么?
不知道该怎么直接查看汇编代码,所以就用OD来查找问题
通过超级字符串查找’|’,找到了输出的地方,然后在代码的周围寻找关键的地方,设置断点
截图+注释如下:
同样是_cdecl调用方式。跟之前VC的明显不同是它把两次a.get_score(a)放在一起执行了,把调用的函数都完成了之后再来处理输出。在004013CD处保存了a的地址,而不是a.socre的值,然后在输出socre时(00401403行)用上了。在输出时也跟VC不同,采用的是地址,而不是立即数,所以输出的是第二次赋给a.socre的值。跟采用VC的不同应该就是编译器处理的不同。
六、g++对以函数为参数的cout输出是怎么处理的
增加函数int tdt (),修改cout行。如下
OD截图如下:
原来对cout<<a.get_score(a).name<<"|"<<a.get_score(a).socre<<"|"<<tdt()<<endl;的处理真的就是首先处理cout行中的函数参数,然后再处理cout。
int tdt()返回的是值,所以后面输出时cout参数进栈的也是值
五、总结
VC++6.0对于cout<<a.get_score(a).name<<"|"<<a.get_score(a).socre<<endl;的处理,关键的是它用的是_cdecl调用方式,而且是参数逐个处理。还有,对于数值,它进栈的是数值,对于字符串,它进栈的是地址,这跟cout的参数里的函数返回的类型无关,而跟它最终要输出的值的类型有关。第一次在命令命令提示符下面输入的name和socre其实是源代码行中的第二个a.get_score(a)。
而采用g++的方式编译,它是先处理cout中的参数,把每个函数都处理完之后再处理cout,所以在输出时,传递cout的参数用的是地址。
对于普通的cout<<a.name<<"|"<<a.socre<<endl;两种编译就没什么差别了。
g++的方式编译,cout<<XXX().b<<XXX().a<<endl;在输出时函数cout的参数进栈的类型跟XXX()返回值同种类型。例如:
cout<<a.get_score(a).name<<"|"<<a.get_score(a).socre<<"|"<<tdt()<<endl;
1、如果tdt()返回的是int类型,cout参数进栈的是实际值
2、如果tdt()返回的是引用,cout参数进栈的是地址。
觉得用cl和g++编译导致输出的不同,根本原因就是cout参数是传递值还是传递地址的不同。
PS:最近才开始学习C++,学习的时候发现了这个小小的问题,最终把问题解决了,知道了到底是怎么回事。先是对_cdecl的调用方式理解不透彻,通过在VC++6.0中看汇编代码,明白是_cdecl方式+cout的参数传递的问题;之后,用g++编译,又出现了问题,同样的_cdecl方式,输出却有差别,通过OD查看生成的exe文件,发现,g++对cout输出的处理跟VC的有差异。写完了总结,发现好像很简单,而且写得有点混乱。也许结果很简单,最重要的是对问题锲而不舍的求知过程。。由于对编译器学习得很少,C++也是刚开始学,所以有一些理解和描述可能有错误。
09.12.13
- 标 题:学习C++时遇到的一个小问题&&解决
- 作 者:cswuyg
- 时 间:2009-12-13 15:22
- 链 接:http://bbs.pediy.com/showthread.php?t=103036