在牛客网看到这样的一个选择题,给出自己的见解
2015-04-14 08:56
232 查看
题目是:
以下程序输出是____。
A 编译阶段报错运行阶段报错
B a = 10, *p = 10
C a = 20, *p = 20
D a = 10, *p = 20
E a = 20, *p = 10
运行时,得到的是答案是D,通过命令objdump -S a.o反汇编:
0000000000400916 <main>:
#include <iostream>
using namespace std;
int main(void)
{
400916: 55 push %rbp
400917: 48 89 e5 mov %rsp,%rbp
40091a: 53 push %rbx
40091b: 48 83 ec 28 sub $0x28,%rsp
40091f: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
400926: 00 00
400928: 48 89 45 e8 mov %rax,-0x18(%rbp)
40092c: 31 c0 xor %eax,%eax
const int a = 10;
40092e: c7 45 dc 0a 00 00 00 movl $0xa,-0x24(%rbp) //把10放入%rbp - 0x24地中存起来
int * p = (int *)(&a);
400935: 48 8d 45 dc lea -0x24(%rbp),%rax //把%rbp - 0x24放入寄存器rax中,注意,此处不是值,而是把地址放入这个寄存器中,rax寄存器保存的是地址。
400939: 48 89 45 e0 mov %rax,-0x20(%rbp) //把寄存器rax的值(也就是上一步//得到的地址)放入地址%rbp
- 0x20中存起来。
*p = 20;
40093d: 48 8b 45 e0 mov -0x20(%rbp),%rax //同上一步,只是反过来赋值无变化
400941: c7 00 14 00 00 00 movl $0x14,(%rax) //把20放入%rbp-0x24地址中存起来,//也就是把存放a的地址中,保存了20.此处应该是a
= 20了,*p = 20。
cout<<"a = "<<a<<", *p = "<<*p<<endl;
400947: 48 8b 45 e0 mov -0x20(%rbp),%rax
40094b: 8b 18 mov (%rax),%ebx
40094d: be 84 0a 40 00 mov $0x400a84,%esi
400952: bf 80 10 60 00 mov $0x601080,%edi
400957: e8 84 fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
40095c: be 0a 00 00 00 mov $0xa,%esi
400961: 48 89 c7 mov %rax,%rdi
400964: e8 17 fe ff ff callq 400780 <_ZNSolsEi@plt>
400969: be 89 0a 40 00 mov $0x400a89,%esi
40096e: 48 89 c7 mov %rax,%rdi
400971: e8 6a fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
400976: 89 de mov %ebx,%esi
400978: 48 89 c7 mov %rax,%rdi
40097b: e8 00 fe ff ff callq 400780 <_ZNSolsEi@plt>
400980: be 10 08 40 00 mov $0x400810,%esi
400985: 48 89 c7 mov %rax,%rdi
400988: e8 73 fe ff ff callq 400800 <_ZNSolsEPFRSoS_E@plt>
return 0;
40098d: b8 00 00 00 00 mov $0x0,%eax
}
从上面的加粗部分汇编以及我的注释中可以看出,在汇编当中还没有进入打印时,在相应的内存中已经对a修改为20了,而且这个值也没有保存在寄存器中,说明后面的打印是需要访问这个地址的。答案是会得到a = 10, *p = 20,也就是说a没有得到更新,我把代码改一下,使得对a的定义改为:
const volatile a = 10.这样,对a的访问强制访问内存,编译执行后得到了a = 20, *p = 20的答案。由此可以看出估计是取a值的时候直接从寄存器里面取值了,但是汇编代码中a的值没有存在寄存器里面,哪里错了?我考虑对修改后的代码进行反汇编,得到:
0000000000400916 <main>:
#include <iostream>
using namespace std;
int main(void)
{
400916: 55 push %rbp
400917: 48 89 e5 mov %rsp,%rbp
40091a: 41 54 push %r12
40091c: 53 push %rbx
40091d: 48 83 ec 20 sub $0x20,%rsp
400921: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
400928: 00 00
40092a: 48 89 45 e8 mov %rax,-0x18(%rbp)
40092e: 31 c0 xor %eax,%eax
const volatile int a = 10;
400930: c7 45 dc 0a 00 00 00 movl $0xa,-0x24(%rbp)
int * p = (int *)(&a);
400937: 48 8d 45 dc lea -0x24(%rbp),%rax
40093b: 48 89 45 e0 mov %rax,-0x20(%rbp)
*p = 20;
40093f: 48 8b 45 e0 mov -0x20(%rbp),%rax
400943: c7 00 14 00 00 00 movl $0x14,(%rax)
cout<<"a = "<<a<<", *p = "<<*p<<endl;
400949: 48 8b 45 e0 mov -0x20(%rbp),%rax
40094d: 8b 18 mov (%rax),%ebx
40094f: 44 8b 65 dc mov -0x24(%rbp),%r12d
400953: be 94 0a 40 00 mov $0x400a94,%esi
400958: bf 80 10 60 00 mov $0x601080,%edi
40095d: e8 7e fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
400962: 44 89 e6 mov %r12d,%esi
400965: 48 89 c7 mov %rax,%rdi
400968: e8 13 fe ff ff callq 400780 <_ZNSolsEi@plt>
40096d: be 99 0a 40 00 mov $0x400a99,%esi
400972: 48 89 c7 mov %rax,%rdi
400975: e8 66 fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
40097a: 89 de mov %ebx,%esi
40097c: 48 89 c7 mov %rax,%rdi
40097f: e8 fc fd ff ff callq 400780 <_ZNSolsEi@plt>
400984: be 10 08 40 00 mov $0x400810,%esi
400989: 48 89 c7 mov %rax,%rdi
40098c: e8 6f fe ff ff callq 400800 <_ZNSolsEPFRSoS_E@plt>
return 0;
400991: b8 00 00 00 00 mov $0x0,%eax
}
对比一下这两个汇编,发现一模一样,看来是我们的objdump命令的问题了,我估计objdump -S命令应该得到的是非常标准没有经过优化的汇编代码(有大神可以可以确定的话,请告诉我,给出你从哪里看到的,比如书本名Pxxx页)。
到这里,结束了,你应该早就明白了,我扯远了。
以下程序输出是____。
B a = 10, *p = 10
C a = 20, *p = 20
D a = 10, *p = 20
E a = 20, *p = 10
运行时,得到的是答案是D,通过命令objdump -S a.o反汇编:
0000000000400916 <main>:
#include <iostream>
using namespace std;
int main(void)
{
400916: 55 push %rbp
400917: 48 89 e5 mov %rsp,%rbp
40091a: 53 push %rbx
40091b: 48 83 ec 28 sub $0x28,%rsp
40091f: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
400926: 00 00
400928: 48 89 45 e8 mov %rax,-0x18(%rbp)
40092c: 31 c0 xor %eax,%eax
const int a = 10;
40092e: c7 45 dc 0a 00 00 00 movl $0xa,-0x24(%rbp) //把10放入%rbp - 0x24地中存起来
int * p = (int *)(&a);
400935: 48 8d 45 dc lea -0x24(%rbp),%rax //把%rbp - 0x24放入寄存器rax中,注意,此处不是值,而是把地址放入这个寄存器中,rax寄存器保存的是地址。
400939: 48 89 45 e0 mov %rax,-0x20(%rbp) //把寄存器rax的值(也就是上一步//得到的地址)放入地址%rbp
- 0x20中存起来。
*p = 20;
40093d: 48 8b 45 e0 mov -0x20(%rbp),%rax //同上一步,只是反过来赋值无变化
400941: c7 00 14 00 00 00 movl $0x14,(%rax) //把20放入%rbp-0x24地址中存起来,//也就是把存放a的地址中,保存了20.此处应该是a
= 20了,*p = 20。
cout<<"a = "<<a<<", *p = "<<*p<<endl;
400947: 48 8b 45 e0 mov -0x20(%rbp),%rax
40094b: 8b 18 mov (%rax),%ebx
40094d: be 84 0a 40 00 mov $0x400a84,%esi
400952: bf 80 10 60 00 mov $0x601080,%edi
400957: e8 84 fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
40095c: be 0a 00 00 00 mov $0xa,%esi
400961: 48 89 c7 mov %rax,%rdi
400964: e8 17 fe ff ff callq 400780 <_ZNSolsEi@plt>
400969: be 89 0a 40 00 mov $0x400a89,%esi
40096e: 48 89 c7 mov %rax,%rdi
400971: e8 6a fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
400976: 89 de mov %ebx,%esi
400978: 48 89 c7 mov %rax,%rdi
40097b: e8 00 fe ff ff callq 400780 <_ZNSolsEi@plt>
400980: be 10 08 40 00 mov $0x400810,%esi
400985: 48 89 c7 mov %rax,%rdi
400988: e8 73 fe ff ff callq 400800 <_ZNSolsEPFRSoS_E@plt>
return 0;
40098d: b8 00 00 00 00 mov $0x0,%eax
}
从上面的加粗部分汇编以及我的注释中可以看出,在汇编当中还没有进入打印时,在相应的内存中已经对a修改为20了,而且这个值也没有保存在寄存器中,说明后面的打印是需要访问这个地址的。答案是会得到a = 10, *p = 20,也就是说a没有得到更新,我把代码改一下,使得对a的定义改为:
const volatile a = 10.这样,对a的访问强制访问内存,编译执行后得到了a = 20, *p = 20的答案。由此可以看出估计是取a值的时候直接从寄存器里面取值了,但是汇编代码中a的值没有存在寄存器里面,哪里错了?我考虑对修改后的代码进行反汇编,得到:
0000000000400916 <main>:
#include <iostream>
using namespace std;
int main(void)
{
400916: 55 push %rbp
400917: 48 89 e5 mov %rsp,%rbp
40091a: 41 54 push %r12
40091c: 53 push %rbx
40091d: 48 83 ec 20 sub $0x20,%rsp
400921: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
400928: 00 00
40092a: 48 89 45 e8 mov %rax,-0x18(%rbp)
40092e: 31 c0 xor %eax,%eax
const volatile int a = 10;
400930: c7 45 dc 0a 00 00 00 movl $0xa,-0x24(%rbp)
int * p = (int *)(&a);
400937: 48 8d 45 dc lea -0x24(%rbp),%rax
40093b: 48 89 45 e0 mov %rax,-0x20(%rbp)
*p = 20;
40093f: 48 8b 45 e0 mov -0x20(%rbp),%rax
400943: c7 00 14 00 00 00 movl $0x14,(%rax)
cout<<"a = "<<a<<", *p = "<<*p<<endl;
400949: 48 8b 45 e0 mov -0x20(%rbp),%rax
40094d: 8b 18 mov (%rax),%ebx
40094f: 44 8b 65 dc mov -0x24(%rbp),%r12d
400953: be 94 0a 40 00 mov $0x400a94,%esi
400958: bf 80 10 60 00 mov $0x601080,%edi
40095d: e8 7e fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
400962: 44 89 e6 mov %r12d,%esi
400965: 48 89 c7 mov %rax,%rdi
400968: e8 13 fe ff ff callq 400780 <_ZNSolsEi@plt>
40096d: be 99 0a 40 00 mov $0x400a99,%esi
400972: 48 89 c7 mov %rax,%rdi
400975: e8 66 fe ff ff callq 4007e0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt>
40097a: 89 de mov %ebx,%esi
40097c: 48 89 c7 mov %rax,%rdi
40097f: e8 fc fd ff ff callq 400780 <_ZNSolsEi@plt>
400984: be 10 08 40 00 mov $0x400810,%esi
400989: 48 89 c7 mov %rax,%rdi
40098c: e8 6f fe ff ff callq 400800 <_ZNSolsEPFRSoS_E@plt>
return 0;
400991: b8 00 00 00 00 mov $0x0,%eax
}
对比一下这两个汇编,发现一模一样,看来是我们的objdump命令的问题了,我估计objdump -S命令应该得到的是非常标准没有经过优化的汇编代码(有大神可以可以确定的话,请告诉我,给出你从哪里看到的,比如书本名Pxxx页)。
到这里,结束了,你应该早就明白了,我扯远了。
相关文章推荐
- 在牛客网看到这样的一个选择题,给出自己的见解
- 用两个线程玩猜数字游戏,第一个线程负责随机给出1~100之间的一个整数,第二个线程负责猜出这个数。要求每当第二个线程给出自己的猜测后,第一个线程都会提示“猜小了”、“猜大了”或“猜对
- 看到老外一个有意思的类,发现自己无知了 ...
- 网易面试题之小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数f(x)为x最大的奇数约数,x为正整数。 例如:f(44) = 11. 现在给出一个N,需要求
- 看到论坛里一个小问题,自己也写了下
- 看到麦兜写的很好,决定自己也来一个
- 自己写了一个js,但是最终不能控制住最后后的提交,前面的还是比较完美,大家看到后,能帮我解决一下吗?
- JAVA--第十周作业编写之一个Teacher类负责给出算术题目,随机给出两个整数并进行运算,并判断回答者的答案是否正确;编写一个GUI类ComputerFrame,回答者可以通过GUI看到题目并给出
- 网易面试题之小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数f(x)为x最大的奇数约数,x为正整数。 例如:f(44) = 11. 现在给出一个N,需要求
- 大学生活应该这样度过之参加一个社团让自己溶入团队——《程序员羊皮卷》连载(11)
- 最近根据别人提示的一个想法,东拼西凑,终于实现了android系统中只能看到自己的系统,我称之为唯一系统。 很多企业做设备或是做产品的或是集成商 其中的一部分设备直接用android智能机。担是又不让
- myeclipse中类和方法创建时添加注释_本来自己想写一个的,但是看到有了,就复制了
- 网易面试题之小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数f(x)为x最大的奇数约数,x为正整数。 例如:f(44) = 11. 现在给出一个N,需要求
- 网上看到了这样一个代码,请问怎么用啊?
- 自己初学数据库的笔记(oracle为主) (附带在网上看到的一个对SQL语句的小结见附件)
- 网易面试题之小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数f(x)为x最大的奇数约数,x为正整数。 例如:f(44) = 11. 现在给出一个N,需要求
- qt连接数据库sqlite3,在网上看到好多人写的都有缺陷,经过努力,自己调试出来了一个
- 看到人问CSDN的采用了什么架构,能够承受这么多访问,就回复了个,这里把自己的的经验也发下,算是给。NET新手一个帮助
- 网易面试题之小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数f(x)为x最大的奇数约数,x为正整数。 例如:f(44) = 11. 现在给出一个N,需要求
- 周鸿祎,高司令 2010-09-28 00:41 27469人阅读 评论(185) 收藏 举报 还是感到有必要将自己的一些想法快速记下来。 首先是对周鸿祎新员工演讲的看法。 就说实话这一点来说,周鸿祎比很多人强。所以我比较喜欢引用他的话,确实比较实在,不装逼。 至于一个公司招人的风格,是公司自己定的,别人也无权评价。有人说周是画大饼,忽悠员工卖命。废话,难道新员工讲话还有别的目的吗? 但我不认为周的选人思路在别的公司可以通行。原因是这样的:近十几年来,我们听到很多人有类似的说法,比如我们公司不要