当前位置: 首页 > 知识库问答 >
问题:

x = x 1是如何被编译器求值的,在汇编中又是如何表示的?

贲功
2023-03-14

我试图理解编译器是如何从表达式i=i 1中“看到”i 1部分的。我理解i=3就是把值3放在变量I的位置内存里。

我对i=i1的猜测是,编译器期望从“=”运算符的右侧得到一个值,因此它从变量i的位置内存中获取值(赋值后为3)并将其加1,“i1”表达式(31=4)的最终结果作为值存储回变量i的位置内存中。这是正确的吗?

如果是,这意味着“=”运算符右侧的任何变量/变量和文字的组合将始终被替换为存储在其中的值,并且这些值可以与来自其他变量/文字的值相加/相减等(如在x 1表达式中),而这些计算的最终结果也将是文字值(例如:5、文字字符串等),并且也将像值一样存储在“=”运算符左侧的单个变量中。

我也很好奇这段代码在汇编中是怎么看到的,i ( i = i 1)的这个增量主要有哪些操作;

#include <stdio.h>
int main()
{
    int i = 3;
    i = i + 1; // i should have the value of 4 stored back in it;
    return 0;
}

共有1个答案

白坚壁
2023-03-14

这不适用于一般情况。这取决于目标平台。如果您想检查程序集,可以使用-S参数和gcc进行检查。当我对你的代码这样做时,它给了我这个:

/tmp$ cat main.s 
    .file   "main.c"
    .text
    .globl  main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movl    $3, -4(%rbp)
    addl    $1, -4(%rbp)
    movl    $0, %eax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Debian 9.2.1-8) 9.2.1 20190909"
    .section    .note.GNU-stack,"",@progbits

对这里发生的事情进行简短的解释。首先,我们推送堆栈指针的值。这样我们以后就可以跳回去。

.cfi_startproc
pushq   %rbp

然后我们用这段代码设置堆栈框架。它对应于声明变量。

.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq    %rsp, %rbp

然后我们有了这个。评论是我的。

movl    $3, -4(%rbp) # i = 3;
addl    $1, -4(%rbp) # i = i + 1;

最后,我们从主函数返回

movl    $0, %eax # Store 0 in the "return register"
popq    %rbp     # Restore stackpointer
.cfi_def_cfa 7, 8
ret              # return

请注意,线条之间没有1-1的关系。即使是非常简单的线条也不行。

另请注意,C 对程序的可观察行为施加要求,而不是对生成的程序集施加要求。例如,编译器可能会删除 main 函数的整个主体,因为变量 i 没有以可观察的方式使用。如果您使用优化,它会。当我使用 -O3 重新编译您的代码时,我得到了这个:

/tmp/$ cat main.s
    .file   "main.c"
    .text
    .section    .text.startup,"ax",@progbits
    .p2align 4
    .globl  main
    .type   main, @function
main:
.LFB11:
    .cfi_startproc
    xorl    %eax, %eax
    ret
    .cfi_endproc
.LFE11:
    .size   main, .-main
    .ident  "GCC: (Debian 9.2.1-8) 9.2.1 20190909"
    .section    .note.GNU-stack,"",@progbits
 类似资料:
  • 问题内容: 被Java编译过程弄糊涂 好的,我知道这一点:我们编写Java源代码,与平台无关的编译器将其转换为字节码,然后与平台相关的jvm将其转换为机器代码。 因此,从一开始,我们就编写Java源代码。编译器javac.exe是.exe文件。.exe文件到底是什么?Java编译器不是用Java编写的,然后为什么会有执行该文件的.exe文件?如果编译器代码是用Java编写的,那么在编译阶段如何执行

  • 至少在GCC中,如果我们提供生成汇编代码的选项,编译器会通过创建一个包含汇编代码的文件来服从。但是,当我们简单地运行命令而没有任何选项时,它不会在内部生成汇编代码吗? 如果是,那么为什么它需要首先生成一个汇编代码,然后将其翻译成机器语言?

  • 问题内容: 我想知道如何检查JIT编译器是否已关闭。我有以下代码旨在关闭JIT编译器。问题是,我不确定它是否确实在这样做。所以我想知道是否有一种方法可以检查JIT是否关闭。我看了Compiler类,但没有类似的方法。 码: 任何帮助或指导将不胜感激。 问题答案: 我不相信您可以在运行时关闭JIT。 如果要认真地对Java程序进行基准测试,则绝对应该忽略前几次运行。在Java中获得可靠的基准测试是一

  • 似乎默认情况下,Clang采用了GNU汇编程序语法。 如何用Clang编译一个汇编文件使用ARM语法像this(指令)和this(指令)?

  • 对象类是每个类的基类,即每个类都扩展了对象类。Object类中有一个公共String toString()方法,而String类中也存在同样的方法。现在,String类还扩展了Object类,方法toString返回一个String类型。 我的问题是-:在编译Object类时,它将搜索String.class,而String类将搜索Object.class,从而创建一种相互依赖的类型。这种依赖是如