代码之家  ›  专栏  ›  技术社区  ›  Vencovsky

c#中x+=1和x=x+1有什么区别吗?

  •  0
  • Vencovsky  · 技术社区  · 4 年前

    在C/C++中,

    expression1 += expression2

    expression1 = expression1 + expression2

    但是,复合赋值表达式并不等同于扩展版本,因为 复合赋值表达式只对expression1求值一次,而扩展版本对expression1求值两次 :在加法运算和赋值运算中。

    Microsoft Docs )


    1. i+=2; , i 将直接修改而不创建任何新对象。
    2. 为了 i=i+2; 一开始会被创造出来。复制的一个将被修改,然后被分配回
            i_copied = i;
            i_copied += 2;
            i = i_copied;
    

    如果没有编译器的任何优化,第二种方法将构造一个无用的实例,从而降低性能。


    在C#中,运算符 += 不允许超载。以及所有 simple types 喜欢 int double 被宣布为 readonly struct

    我想知道在C#,有吗 强迫的某种表达 要修改的对象(至少对于简单类型) 直接地 ,而不创建任何无用的实例。

    而且,C#-编译器是否有可能优化表达式 x=x+y x+=y 正如所料,如果构造器和解构器没有副作用。

    0 回复  |  直到 4 年前
        1
  •  5
  •   Theraot    4 年前

    当您将C#编译成.NET程序集时,代码是用MSIL(Microsoft中间语言)编写的。这使得代码可以移植。NET运行时将对其进行JIT编译以供执行。

    MSIL是一种堆栈语言。它不知道目标硬件的细节(比如CPU有多少个寄存器)。只有一种方法可以写这个加法:

        ldloc.0
        ldloc.1
        add
        stloc.0
    

    : add 从堆栈中弹出两个元素,将它们相加,然后将结果推回到堆栈中。

    x=x+y x+=y 将产生相同的代码。


    当然,之后会有一些优化。JIT编译器将把它转换成实际的机器代码。

    SharpLab :

    mov ecx, [ebp-4]
    add ecx, [ebp-8]
    mov [ebp-4], ecx
    

    我们收到了 [ebp-4] ecx ,添加 [ebp-8] ecx公司 回到 【ebp-4】 .

    ecx公司 一个无用的例子?


    好吧,那是SharpLab,那是JIT。理论上,不同的编译器可以在不同的平台上将代码转换成不同的内容。

    您可以将.NET代码AOT编译为本机映像,这在优化时会更具攻击性。尽管如此,我不认为你将如何改进一个简单的加法。 哦,我知道,它可能会看到您不使用这个值并删除它,或者可能会看到您总是添加相同的值并用常量替换它。

    值得注意的是,现代的.NETJIT能够在执行过程中继续优化代码(它将很快生成优化效果不佳的本机代码版本,稍后-一旦准备就绪-将其替换为更好的版本)。这个决定来自这样一个事实:在JIT运行时,性能取决于创建本机代码所需的时间和本机代码运行所需的时间。


    C++

    x = x + y x += y 使用 godbolt

        mov     eax, DWORD PTR [rbp-8]
        add     DWORD PTR [rbp-4], eax
        mov     eax, DWORD PTR [rbp-4]
    

    说明书 mov , 添加 匹配我们从夏普实验室得到的,有不同的寄存器选择。

    :x86-64 gcc 9.3,带 -g -o /tmp/compiler-explorer-compiler2020424-22672-17cap6k.bjoj/output.s -masm=intel -S -fdiagnostics-color=always /tmp/compiler-explorer-compiler2020424-22672-17cap6k.bjoj/example.cpp

    添加编译器选项 -O

        2
  •  3
  •   György Kőszeg    4 年前

    要回答这些问题,您可以使用SharpLab。

    作为 you can see 在这两种情况下,生成的IL和JITted代码都是相同的。

        3
  •  2
  •   Samuel Vidal    4 年前

    它是严格等价的。形式 x += y 语法糖是用来 x = x + y .