在牛客网看到这样的一个选择题,给出自己的见解

来源:互联网 发布:好听的基督教网络歌曲 编辑:程序博客网 时间:2024/06/05 09:51

题目是:

以下程序输出是____。

1
2
3
4
5
6
7
8
9
10
#include <iostream> 
using namespace std; 
int main(void
    constint a = 10
    int* p = (int *)(&a); 
    *p =20
    cout<<"a = "<<a<<", *p = "<<*p<<endl; 
    return0
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页)。
      到这里,结束了,你应该早就明白了,我扯远了。
0 0
原创粉丝点击