a=3, 为什么计算a+=a-=a*a时,C运行的结果是-12,而js是-3?

新手上路,请多包涵

如题,不太明白js哪里出了问题。

#include <stdio.h>

int main(void)
{
    int a=3;
    a+=a-=a*a;
    printf("%d",a);
    return 0;
}

C运行环境: GCC 9.3.0
在线调试链接: https://wandbox.org/permlink/...

var a=3;
console.log(a+=a-=a*a);

JavaScript运行环境: Node.js 14.0.0
在线调试链接: https://wandbox.org/permlink/...

阅读 2.3k
2 个回答

C 的执行可以通过生成 assembly 来分析

...
 8     pushq   %rbp
  9     .cfi_def_cfa_offset 16
 10     .cfi_offset %rbp, -16
 11     movq    %rsp, %rbp
 12     .cfi_def_cfa_register %rbp
 13     subq    $16, %rsp
 14     leaq    L_.str(%rip), %rdi
 15     movl    $0, -4(%rbp)  ; 放0到 内存(-4)位置
 16     movl    $3, -8(%rbp)   ; 放3 到内存 (-8)的位置
 17     movl    -8(%rbp), %eax ; 把内存 (-8)的位置的3 放到 eax 寄存器
 18     imull   -8(%rbp), %eax  ; 3*3 结果放到 eax, eax=9
 19     movl    -8(%rbp), %ecx  ; 3 放到 ecx 寄存器
 20     subl    %eax, %ecx   ; 3-9=-6 放到 ecx
 21     movl    %ecx, -8(%rbp)  ; -6 放到内存(-8)的位置
 22     addl    -8(%rbp), %ecx  ; 内存(-8)的位置 -6加上 ecx里的-6, 结果-12放到 ecx
 23     movl    %ecx, -8(%rbp)
 24     movl    -8(%rbp), %esi
 25     movb    $0, %al
 26     callq   _printf
 27     xorl    %ecx, %ecx
 28     movl    %eax, -12(%rbp)         ## 4-byte Spill
 29     movl    %ecx, %eax
 30     addq    $16, %rsp
 31     popq    %rbp
 32     retq
 33     .cfi_endproc

见上面的注释。可以把 eax 和 ecx 看成是临时变量就好理解了。

a=3
eax = a   // 3
eax = eax * a = 9
ecx = a   // 3
ecx = ecx -eax // -6
a = ecx  // -6
ecx = a+ecx //-12

关键在于 C 语言从右向左执行完第一个赋值语句时,a 已经是 -6,而 js 是把连续赋值当成一个表达式来执行。中间少了对 a 赋值的过程。

即 js 的执行过程可以理解成:

var a=3,b=a,c=a;
console.log(c+=b-=a*a);
//c = -3

而 c 语言则是两阶段引入变量

int a=3;
a-=a*a // b = a - a*a
a+=a   // c = b+b

JS没有结合率,JS是面向对象的单线程语言

var a=3;a+=a
6
var a=3;a+=a-=a
3
var a=3;a+=a-=a*a
-3
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题