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

题目是:

以下程序输出是____。

1
2
3
4
5
6
7
8
9
10
#include <iostream> 
using namespace std; 
int main( void
     const int a = 10
     int * p = ( int *)(&a); 
     *p = 20
     cout<< "a = " <<a<< ", *p = " <<*p<<endl; 
     return 0
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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值