zoukankan      html  css  js  c++  java
  • const 值被更改的问题

    今天同事问了关于const 值被更改的问题,这个问题在面试中也会经常被问到,所以专门写篇博客总结下。

    代码如下

    输出结果:a:10 p:20

    简单分析

    其实针对该问题,原因比较简单,在printf调用中,由于a是常量,编译器做了优化,将a的值直接替换为10,所以在后续对a的内存位置进行更改为20时,并未对printf的a参数影响。当然,同事并未相信我的分析,我只能调用汇编后的代码进行分析。

    深度分析:

    1. 生成汇编代码:

    1
    g++ -S test.cpp   # 输出的汇编代码位于test.s中

    2. 汇编代码如下:


    根据第26行,验证了我上述的分析,此时同事想让我讲下整个汇编代码的逻辑(我心里暗喜,刚好最近在上@林士鼎 的课程,顺便复习下)
    3. 函数调用的知识
    理解函数调用栈,有几个概念需要事先明确:
    a. 栈的增长方式由高到低(大学课本里早就会背了,但是要真正理解)
    b. 参数传递方式:寄存器 + 栈
    c. %rsp : 栈头指针 , push pop会更改对应的指针值
    d. %rbp : 帧指针, 这个概念非常重要,当前函数的栈的起始位置,
    使用%rbp + offset访问局部变量及传递的参数,下面这张图是@林士鼎 老师的课件中某个图

    4. 汇编分析:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    main:
    .LFB2:
    pushq %rbp    # 将原来的帧指针保存
    .LCFI0:
    movq %rsp, %rbp   # 将当前%rsp 保存至%rbp, 当前帧
    .LCFI1:
    subq $32, %rsp   # 将栈下移32Bytes, 这32字节保存了main的参数和main中局部变量
    .LCFI2:
    movl %edi, -4(%rbp)   # 取 argc的值
    movq %rsi, -16(%rbp)    # 取argv的值, 为何会占12Bytes呢? 后续分析
    movl $10, -20(%rbp)    # 将10赋值给a
    leaq -20(%rbp), %rax   #取a的地址到%rax
    movq %rax, -32(%rbp)     #将a的地址赋值给p(int *), 32的偏移有待分析
    movq -32(%rbp), %rax    # 去p的值到%rax
    movl $20, (%rax)     # 对*p赋值
    movq -32(%rbp), %rax
    movl (%rax), %edx   #这两步相当于*p,同时将其赋值到寄存器作为printf的参数
    movl $10, %esi     #传递10参数(其实是a)
    movl $.LC0, %edi    # "a:%d p:%d "
    movl $0, %eax   #这个作用稍后分析
    call printf
    movl $0, %eax  #main函数的返回值
    leave
    ret

    变量在栈的位置分布情况:


    5. 其他问题分析:

    a. 为何argv 和 p在栈的位置偏移异常,这里主要是因为argc 和a 的大小为4Bytes,  而系统是64Bits, 所以存在8Bytes对齐,
    这里可以验证,在a后面单独声明一个b变量,发现其在栈的空间刚好为间隙的位置

    b.  movl $0, %eax   这句话的作用:当对于变参的参数传递时,%eax标示的使用vector register的数目(可以向printf传递float类型参数进行验证)

    参考资料:

    1. http://stackoverflow.com/questions/6212665/why-is-eax-zeroed-before-a-call-to-printf

    2. http://yaronspace.cn/blog/archives/1347

  • 相关阅读:
    【weka应用技术与实践】过滤器
    【软件分析与挖掘】Vision of Software Clone Management: Past, Present, and Future (Keynote Paper)
    【软件分析与挖掘】Multiple kernel ensemble learning for software defect prediction
    【Thinking in Java-CHAPTER 3】操作符
    【软件分析与挖掘】A Comparative Study of Supervised Learning Algorithms for Re-opened Bug Prediction
    【Thinking in Java-CHAPTER 1&&2】对象导论&&一切都是对象
    【cs229-Lecture20】策略搜索
    【cs229-Lecture19】微分动态规划
    【cs229-Lecture18】线性二次型调节控制
    【cs229-Lecture17】离散与维数灾难
  • 原文地址:https://www.cnblogs.com/mysqlinternal/p/12764639.html
Copyright © 2011-2022 走看看